<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-CN">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.3" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png?v=5.1.3">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png?v=5.1.3">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.3" color="#222">





  <meta name="keywords" content="Hexo, NexT" />




  


  <link rel="alternate" href="/atom.xml" title="理想-咸鱼" type="application/atom+xml" />






<meta name="description" content="一些简单的想法">
<meta property="og:type" content="website">
<meta property="og:title" content="理想-咸鱼">
<meta property="og:url" content="http://yoursite.com/page/2/index.html">
<meta property="og:site_name" content="理想-咸鱼">
<meta property="og:description" content="一些简单的想法">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="bigfish">
<meta property="article:tag" content="python c c++ go lua 足球">
<meta name="twitter:card" content="summary">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '5.1.3',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/page/2/"/>





  <title>理想-咸鱼</title>
  








<meta name="generator" content="Hexo 4.2.0"></head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left 
  page-home">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">理想-咸鱼</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">鱼翔浅底</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            Archives
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            Tags
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            Categories
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/12/20/tornado-yuan-ma-zhi-iostream/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/12/20/tornado-yuan-ma-zhi-iostream/" itemprop="url">tornado源码之iostream</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-12-20T16:46:51+08:00">
                2018-12-20
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  2.8k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  15
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="iostream-py"><a href="#iostream-py" class="headerlink" title="iostream.py"></a>iostream.py</h1><p>A utility class to write to and read from a non-blocking socket.</p>
<p>IOStream 对 socket 进行包装，采用注册回调方式实现非阻塞。<br>通过接口注册各个事件回调</p>
<ul>
<li>_read_callback</li>
<li>_write_callback</li>
<li>_close_callback</li>
<li>_connect_callback</li>
</ul>
<p>ioloop 中 socket 事件发生后，调用 IOStream._handle_events 方法，对事件进行分发。<br>对应的事件处理过程中，如果满足注册的回调条件，则调用回调函数<br>回调函数在 IOStream._handle_events 中被调用</p>
<h2 id="contents"><a href="#contents" class="headerlink" title="contents"></a>contents</h2><ul>
<li><a href="#iostreampy">iostream.py</a><ul>
<li><a href="#contents">contents</a></li>
<li><a href="#example">example</a></li>
<li><a href="#head">head</a></li>
<li><a href="#iostreaminit">IOStream.__init__</a></li>
<li><a href="#iostreamconnect">IOStream.connect</a></li>
<li><a href="#iostreamreaduntil">IOStream.read_until</a></li>
<li><a href="#iostreamreadbytes">IOStream.read_bytes</a></li>
<li><a href="#iostreamwrite">IOStream.write</a></li>
<li><a href="#iostreamclose">IOStream.close</a></li>
<li><a href="#iostreamhandleevents">IOStream._handle_events</a></li>
<li><a href="#iostreamruncallback">IOStream._run_callback</a></li>
<li><a href="#iostreamruncallback-1">IOStream._run_callback</a></li>
<li><a href="#iostreamreadfromsocket">IOStream._read_from_socket</a></li>
<li><a href="#iostreamreadtobuffer">IOStream._read_to_buffer</a></li>
<li><a href="#iostreamreadfrombuffer">IOStream._read_from_buffer</a></li>
<li><a href="#iostreamhandleconnect">IOStream._handle_connect</a></li>
<li><a href="#iostreamhandlewrite">IOStream._handle_write</a></li>
<li><a href="#iostreamconsume">IOStream._consume</a></li>
<li><a href="#iostreamaddiostate">IOStream._add_io_state</a></li>
<li><a href="#iostreamreadbuffersize">IOStream._read_buffer_size</a></li>
<li><a href="#copyright">copyright</a></li>
</ul>
</li>
</ul>
<h2 id="example"><a href="#example" class="headerlink" title="example"></a>example</h2><p>一个简单的 IOStream 客户端示例<br><strong>由此可见， IOStream 是一个异步回调链</strong></p>
<ol>
<li>创建 socket</li>
<li>创建 IOStream 对象</li>
<li>连接到主机，传入连接成功后回调函数 send_request</li>
<li>socket 输出数据请求页面，读取 head, 传入读取 head 成功后回调函数 on_headers</li>
<li>继续读取 body, 传入读取 body 成功后回调函数 on_body</li>
<li>关闭 stream，关闭 ioloop</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> ioloop</span><br><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> iostream</span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">send_request</span><span class="params">()</span>:</span></span><br><span class="line">    stream.write(<span class="string">"GET / HTTP/1.0\r\nHost: baidu.com\r\n\r\n"</span>)</span><br><span class="line">    stream.read_until(<span class="string">"\r\n\r\n"</span>, on_headers)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">on_headers</span><span class="params">(data)</span>:</span></span><br><span class="line">    headers = &#123;&#125;</span><br><span class="line">    <span class="keyword">for</span> line <span class="keyword">in</span> data.split(<span class="string">"\r\n"</span>):</span><br><span class="line">        parts = line.split(<span class="string">":"</span>)</span><br><span class="line">        <span class="keyword">if</span> len(parts) == <span class="number">2</span>:</span><br><span class="line">            headers[parts[<span class="number">0</span>].strip()] = parts[<span class="number">1</span>].strip()</span><br><span class="line">    stream.read_bytes(int(headers[<span class="string">"Content-Length"</span>]), on_body)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">on_body</span><span class="params">(data)</span>:</span></span><br><span class="line">    <span class="keyword">print</span> data</span><br><span class="line">    stream.close()</span><br><span class="line">    ioloop.IOLoop.instance().stop()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, <span class="number">0</span>)</span><br><span class="line">stream = iostream.IOStream(s)</span><br><span class="line">stream.connect((<span class="string">"baidu.com"</span>, <span class="number">80</span>), send_request)</span><br><span class="line">ioloop.IOLoop.instance().start()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># html&gt;</span></span><br><span class="line"><span class="comment"># &lt;meta http-equiv="refresh" content="0;        url=http://www.baidu.com/"&gt;</span></span><br><span class="line"><span class="comment"># &lt;/html&gt;</span></span><br></pre></td></tr></table></figure>

<h2 id="head"><a href="#head" class="headerlink" title="head"></a>head</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> with_statement</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> collections</span><br><span class="line"><span class="keyword">import</span> errno</span><br><span class="line"><span class="keyword">import</span> logging</span><br><span class="line"><span class="keyword">import</span> socket</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> ioloop</span><br><span class="line"><span class="keyword">from</span> tornado <span class="keyword">import</span> stack_context</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="keyword">import</span> ssl <span class="comment"># Python 2.6+</span></span><br><span class="line"><span class="keyword">except</span> ImportError:</span><br><span class="line">    ssl = <span class="literal">None</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-init"><a href="#IOStream-init" class="headerlink" title="IOStream.__init__"></a>IOStream.__init__</h2><p>包装 socket 类<br>关键语句 <code>self.io_loop.add_handler(self.socket.fileno(), self._handle_events, self._state)</code> 将自身的_handle_events 加入到全局 ioloop poll 事件回调<br>此时只注册了 ERROR 类型事件</p>
<p>_read_buffer: 读缓冲</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">IOStream</span><span class="params">(object)</span>:</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, socket, io_loop=None, max_buffer_size=<span class="number">104857600</span>,</span></span></span><br><span class="line"><span class="function"><span class="params">                 read_chunk_size=<span class="number">4096</span>)</span>:</span></span><br><span class="line">        self.socket = socket</span><br><span class="line">        self.socket.setblocking(<span class="literal">False</span>)</span><br><span class="line">        self.io_loop = io_loop <span class="keyword">or</span> ioloop.IOLoop.instance()</span><br><span class="line">        self.max_buffer_size = max_buffer_size</span><br><span class="line">        self.read_chunk_size = read_chunk_size</span><br><span class="line">        self._read_buffer = collections.deque()</span><br><span class="line">        self._write_buffer = collections.deque()</span><br><span class="line">        self._write_buffer_frozen = <span class="literal">False</span></span><br><span class="line">        self._read_delimiter = <span class="literal">None</span></span><br><span class="line">        self._read_bytes = <span class="literal">None</span></span><br><span class="line">        self._read_callback = <span class="literal">None</span></span><br><span class="line">        self._write_callback = <span class="literal">None</span></span><br><span class="line">        self._close_callback = <span class="literal">None</span></span><br><span class="line">        self._connect_callback = <span class="literal">None</span></span><br><span class="line">        self._connecting = <span class="literal">False</span></span><br><span class="line">        self._state = self.io_loop.ERROR</span><br><span class="line">        <span class="keyword">with</span> stack_context.NullContext():</span><br><span class="line">            self.io_loop.add_handler(</span><br><span class="line">                self.socket.fileno(), self._handle_events, self._state)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-connect"><a href="#IOStream-connect" class="headerlink" title="IOStream.connect"></a>IOStream.connect</h2><p>连接 socket 到远程地址，非阻塞模式</p>
<ol>
<li>连接 socket</li>
<li>注册连接完成回调</li>
<li>poll 增加 socket 写事件</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">connect</span><span class="params">(self, address, callback=None)</span>:</span></span><br><span class="line">    <span class="string">"""Connects the socket to a remote address without blocking.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    May only be called if the socket passed to the constructor was</span></span><br><span class="line"><span class="string">    not previously connected.  The address parameter is in the</span></span><br><span class="line"><span class="string">    same format as for socket.connect, i.e. a (host, port) tuple.</span></span><br><span class="line"><span class="string">    If callback is specified, it will be called when the</span></span><br><span class="line"><span class="string">    connection is completed.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Note that it is safe to call IOStream.write while the</span></span><br><span class="line"><span class="string">    connection is pending, in which case the data will be written</span></span><br><span class="line"><span class="string">    as soon as the connection is ready.  Calling IOStream read</span></span><br><span class="line"><span class="string">    methods before the socket is connected works on some platforms</span></span><br><span class="line"><span class="string">    but is non-portable.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    self._connecting = <span class="literal">True</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        self.socket.connect(address)</span><br><span class="line">    <span class="keyword">except</span> socket.error, e:</span><br><span class="line">        <span class="comment"># In non-blocking mode connect() always raises an exception</span></span><br><span class="line">        <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">not</span> <span class="keyword">in</span> (errno.EINPROGRESS, errno.EWOULDBLOCK):</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line">    self._connect_callback = stack_context.wrap(callback)</span><br><span class="line">    self._add_io_state(self.io_loop.WRITE)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-until"><a href="#IOStream-read-until" class="headerlink" title="IOStream.read_until"></a>IOStream.read_until</h2><ol>
<li>注册读完成回调</li>
<li>尝试从缓冲中读</li>
<li>从 socket 中读到缓冲区</li>
<li>重复 2,3, 没有数据则退出</li>
<li>将 socket 读事件加入 poll</li>
</ol>
<p>如果缓存中数据满足条件，则直接执行 callback 并返回，<br>否则，保存 callback 函数下次 read 事件发生时，_handle_events 处理读事件时，再进行检测及调用</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_until</span><span class="params">(self, delimiter, callback)</span>:</span></span><br><span class="line">    <span class="string">"""Call callback when we read the given delimiter."""</span></span><br><span class="line">    <span class="keyword">assert</span> <span class="keyword">not</span> self._read_callback, <span class="string">"Already reading"</span></span><br><span class="line">    self._read_delimiter = delimiter</span><br><span class="line">    self._read_callback = stack_context.wrap(callback)</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="comment"># See if we've already got the data from a previous read</span></span><br><span class="line">        <span class="keyword">if</span> self._read_from_buffer():</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        self._check_closed()</span><br><span class="line">        <span class="keyword">if</span> self._read_to_buffer() == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">    self._add_io_state(self.io_loop.READ)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-bytes"><a href="#IOStream-read-bytes" class="headerlink" title="IOStream.read_bytes"></a>IOStream.read_bytes</h2><p>参考 read_until，读限定字节</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">read_bytes</span><span class="params">(self, num_bytes, callback)</span>:</span></span><br><span class="line">    <span class="string">"""Call callback when we read the given number of bytes."""</span></span><br><span class="line">    <span class="keyword">assert</span> <span class="keyword">not</span> self._read_callback, <span class="string">"Already reading"</span></span><br><span class="line">    <span class="keyword">if</span> num_bytes == <span class="number">0</span>:</span><br><span class="line">        callback(<span class="string">""</span>)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    self._read_bytes = num_bytes</span><br><span class="line">    self._read_callback = stack_context.wrap(callback)</span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="keyword">if</span> self._read_from_buffer():</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        self._check_closed()</span><br><span class="line">        <span class="keyword">if</span> self._read_to_buffer() == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">    self._add_io_state(self.io_loop.READ)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-write"><a href="#IOStream-write" class="headerlink" title="IOStream.write"></a>IOStream.write</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">write</span><span class="params">(self, data, callback=None)</span>:</span></span><br><span class="line">    <span class="string">"""Write the given data to this stream.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    If callback is given, we call it when all of the buffered write</span></span><br><span class="line"><span class="string">    data has been successfully written to the stream. If there was</span></span><br><span class="line"><span class="string">    previously buffered write data and an old write callback, that</span></span><br><span class="line"><span class="string">    callback is simply overwritten with this new callback.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    self._check_closed()</span><br><span class="line">    self._write_buffer.append(data)</span><br><span class="line">    self._add_io_state(self.io_loop.WRITE)</span><br><span class="line">    self._write_callback = stack_context.wrap(callback)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">set_close_callback</span><span class="params">(self, callback)</span>:</span></span><br><span class="line">    <span class="string">"""Call the given callback when the stream is closed."""</span></span><br><span class="line">    self._close_callback = stack_context.wrap(callback)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-close"><a href="#IOStream-close" class="headerlink" title="IOStream.close"></a>IOStream.close</h2><ol>
<li>从 ioloop 移除 socket 事件</li>
<li>关闭 socket</li>
<li>调用关闭回调</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">close</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Close this stream."""</span></span><br><span class="line">    <span class="keyword">if</span> self.socket <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        self.io_loop.remove_handler(self.socket.fileno())</span><br><span class="line">        self.socket.close()</span><br><span class="line">        self.socket = <span class="literal">None</span></span><br><span class="line">        <span class="keyword">if</span> self._close_callback:</span><br><span class="line">            self._run_callback(self._close_callback)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">reading</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Returns true if we are currently reading from the stream."""</span></span><br><span class="line">    <span class="keyword">return</span> self._read_callback <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">writing</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Returns true if we are currently writing to the stream."""</span></span><br><span class="line">    <span class="keyword">return</span> bool(self._write_buffer)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">closed</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">return</span> self.socket <span class="keyword">is</span> <span class="literal">None</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-handle-events"><a href="#IOStream-handle-events" class="headerlink" title="IOStream._handle_events"></a>IOStream._handle_events</h2><p>核心回调<br>任何类型的 socket 事件触发 ioloop 回调_handle_events，然后在_handle_events 再进行分发<br>值得注意的是，IOStream 不处理连接请求的 read 事件<br><strong>注意</strong><br>作为服务端，默认代理的是已经建立连接的 socket</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># HTTPServer.\_handle_events</span></span><br><span class="line"><span class="comment"># connection 为已经accept的连接</span></span><br><span class="line">stream = iostream.IOStream(connection, io_loop=self.io_loop)</span><br></pre></td></tr></table></figure>

<p>作为客户端，需要手动调用 IOStream.connect，连接成功后，成功回调在 write 事件中处理</p>
<p>这个实现比较别扭</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_events</span><span class="params">(self, fd, events)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">        logging.warning(<span class="string">"Got events for closed stream %d"</span>, fd)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="comment"># 处理读事件，调用已注册回调</span></span><br><span class="line">        <span class="keyword">if</span> events &amp; self.io_loop.READ:</span><br><span class="line">            self._handle_read()</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        <span class="comment"># 处理写事件，如果是刚建立连接，调用连接建立回调</span></span><br><span class="line">        <span class="keyword">if</span> events &amp; self.io_loop.WRITE:</span><br><span class="line">            <span class="keyword">if</span> self._connecting:</span><br><span class="line">                self._handle_connect()</span><br><span class="line">            self._handle_write()</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        <span class="comment"># 错误事件，关闭 socket</span></span><br><span class="line">        <span class="keyword">if</span> events &amp; self.io_loop.ERROR:</span><br><span class="line">            self.close()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        state = self.io_loop.ERROR</span><br><span class="line">        <span class="keyword">if</span> self.reading():</span><br><span class="line">            state |= self.io_loop.READ</span><br><span class="line">        <span class="keyword">if</span> self.writing():</span><br><span class="line">            state |= self.io_loop.WRITE</span><br><span class="line">        <span class="keyword">if</span> state != self._state:</span><br><span class="line">            self._state = state</span><br><span class="line">            self.io_loop.update_handler(self.socket.fileno(), self._state)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        logging.error(<span class="string">"Uncaught exception, closing connection."</span>,</span><br><span class="line">                      exc_info=<span class="literal">True</span>)</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">raise</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-run-callback"><a href="#IOStream-run-callback" class="headerlink" title="IOStream._run_callback"></a>IOStream._run_callback</h2><p>执行回调</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_run_callback</span><span class="params">(self, callback, *args, **kwargs)</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="comment"># Use a NullContext to ensure that all StackContexts are run</span></span><br><span class="line">        <span class="comment"># inside our blanket exception handler rather than outside.</span></span><br><span class="line">        <span class="keyword">with</span> stack_context.NullContext():</span><br><span class="line">            callback(*args, **kwargs)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        logging.error(<span class="string">"Uncaught exception, closing connection."</span>,</span><br><span class="line">                      exc_info=<span class="literal">True</span>)</span><br><span class="line">        <span class="comment"># Close the socket on an uncaught exception from a user callback</span></span><br><span class="line">        <span class="comment"># (It would eventually get closed when the socket object is</span></span><br><span class="line">        <span class="comment"># gc'd, but we don't want to rely on gc happening before we</span></span><br><span class="line">        <span class="comment"># run out of file descriptors)</span></span><br><span class="line">        self.close()</span><br><span class="line">        <span class="comment"># Re-raise the exception so that IOLoop.handle_callback_exception</span></span><br><span class="line">        <span class="comment"># can see it and log the error</span></span><br><span class="line">        <span class="keyword">raise</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-run-callback-1"><a href="#IOStream-run-callback-1" class="headerlink" title="IOStream._run_callback"></a>IOStream._run_callback</h2><p>读回调</p>
<ol>
<li>从 socket 读取数据到缓存</li>
<li>无数据, socket 关闭</li>
<li>检测是否满足 read_until read_bytes</li>
<li>满足则执行对应回调</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_read</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="comment"># Read from the socket until we get EWOULDBLOCK or equivalent.</span></span><br><span class="line">            <span class="comment"># SSL sockets do some internal buffering, and if the data is</span></span><br><span class="line">            <span class="comment"># sitting in the SSL object's buffer select() and friends</span></span><br><span class="line">            <span class="comment"># can't see it; the only way to find out if it's there is to</span></span><br><span class="line">            <span class="comment"># try to read it.</span></span><br><span class="line">            result = self._read_to_buffer()</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            self.close()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        <span class="keyword">if</span> result == <span class="number">0</span>:</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">if</span> self._read_from_buffer():</span><br><span class="line">                <span class="keyword">return</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-from-socket"><a href="#IOStream-read-from-socket" class="headerlink" title="IOStream._read_from_socket"></a>IOStream._read_from_socket</h2><p>从 socket 读取数据</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_read_from_socket</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Attempts to read from the socket.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Returns the data read or None if there is nothing to read.</span></span><br><span class="line"><span class="string">    May be overridden in subclasses.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        chunk = self.socket.recv(self.read_chunk_size)</span><br><span class="line">    <span class="keyword">except</span> socket.error, e:</span><br><span class="line">        <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">in</span> (errno.EWOULDBLOCK, errno.EAGAIN):</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> chunk:</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">    <span class="keyword">return</span> chunk</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-to-buffer"><a href="#IOStream-read-to-buffer" class="headerlink" title="IOStream._read_to_buffer"></a>IOStream._read_to_buffer</h2><p>从 socket 读取数据存入缓存</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_read_to_buffer</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Reads from the socket and appends the result to the read buffer.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Returns the number of bytes read.  Returns 0 if there is nothing</span></span><br><span class="line"><span class="string">    to read (i.e. the read returns EWOULDBLOCK or equivalent).  On</span></span><br><span class="line"><span class="string">    error closes the socket and raises an exception.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        chunk = self._read_from_socket()</span><br><span class="line">    <span class="keyword">except</span> socket.error, e:</span><br><span class="line">        <span class="comment"># ssl.SSLError is a subclass of socket.error</span></span><br><span class="line">        logging.warning(<span class="string">"Read error on %d: %s"</span>,</span><br><span class="line">                        self.socket.fileno(), e)</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">raise</span></span><br><span class="line">    <span class="keyword">if</span> chunk <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    self._read_buffer.append(chunk)</span><br><span class="line">    <span class="keyword">if</span> self._read_buffer_size() &gt;= self.max_buffer_size:</span><br><span class="line">        logging.error(<span class="string">"Reached maximum read buffer size"</span>)</span><br><span class="line">        self.close()</span><br><span class="line">        <span class="keyword">raise</span> IOError(<span class="string">"Reached maximum read buffer size"</span>)</span><br><span class="line">    <span class="keyword">return</span> len(chunk)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-from-buffer"><a href="#IOStream-read-from-buffer" class="headerlink" title="IOStream._read_from_buffer"></a>IOStream._read_from_buffer</h2><p>从缓冲中过滤数据<br>检测是否满足结束条件 (read_until/read_bytes)，满足则调用之前注册的回调<br>采用的是查询方式</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_read_from_buffer</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="string">"""Attempts to complete the currently-pending read from the buffer.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Returns True if the read was completed.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="keyword">if</span> self._read_bytes:</span><br><span class="line">        <span class="keyword">if</span> self._read_buffer_size() &gt;= self._read_bytes:</span><br><span class="line">            num_bytes = self._read_bytes</span><br><span class="line">            callback = self._read_callback</span><br><span class="line">            self._read_callback = <span class="literal">None</span></span><br><span class="line">            self._read_bytes = <span class="literal">None</span></span><br><span class="line">            self._run_callback(callback, self._consume(num_bytes))</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line">    <span class="keyword">elif</span> self._read_delimiter:</span><br><span class="line">        _merge_prefix(self._read_buffer, sys.maxint)</span><br><span class="line">        loc = self._read_buffer[<span class="number">0</span>].find(self._read_delimiter)</span><br><span class="line">        <span class="keyword">if</span> loc != <span class="number">-1</span>:</span><br><span class="line">            callback = self._read_callback</span><br><span class="line">            delimiter_len = len(self._read_delimiter)</span><br><span class="line">            self._read_callback = <span class="literal">None</span></span><br><span class="line">            self._read_delimiter = <span class="literal">None</span></span><br><span class="line">            self._run_callback(callback,</span><br><span class="line">                               self._consume(loc + delimiter_len))</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">False</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-handle-connect"><a href="#IOStream-handle-connect" class="headerlink" title="IOStream._handle_connect"></a>IOStream._handle_connect</h2><p>调用连接建立回调，并清除连接中标志</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_connect</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> self._connect_callback <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">        callback = self._connect_callback</span><br><span class="line">        self._connect_callback = <span class="literal">None</span></span><br><span class="line">        self._run_callback(callback)</span><br><span class="line">    self._connecting = <span class="literal">False</span></span><br></pre></td></tr></table></figure>

<h2 id="IOStream-handle-write"><a href="#IOStream-handle-write" class="headerlink" title="IOStream._handle_write"></a>IOStream._handle_write</h2><p>写事件</p>
<ol>
<li>从缓冲区获取限定范围内数据</li>
<li>调用 socket.send 输出数据</li>
<li>如果数据发送我且已注册回调，调用发送完成回调</li>
</ol>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_handle_write</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> self._write_buffer:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> self._write_buffer_frozen:</span><br><span class="line">                <span class="comment"># On windows, socket.send blows up if given a</span></span><br><span class="line">                <span class="comment"># write buffer that's too large, instead of just</span></span><br><span class="line">                <span class="comment"># returning the number of bytes it was able to</span></span><br><span class="line">                <span class="comment"># process.  Therefore we must not call socket.send</span></span><br><span class="line">                <span class="comment"># with more than 128KB at a time.</span></span><br><span class="line">                _merge_prefix(self._write_buffer, <span class="number">128</span> * <span class="number">1024</span>)</span><br><span class="line">            num_bytes = self.socket.send(self._write_buffer[<span class="number">0</span>])</span><br><span class="line">            self._write_buffer_frozen = <span class="literal">False</span></span><br><span class="line">            _merge_prefix(self._write_buffer, num_bytes)</span><br><span class="line">            self._write_buffer.popleft()</span><br><span class="line">        <span class="keyword">except</span> socket.error, e:</span><br><span class="line">            <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">in</span> (errno.EWOULDBLOCK, errno.EAGAIN):</span><br><span class="line">                <span class="comment"># With OpenSSL, after send returns EWOULDBLOCK,</span></span><br><span class="line">                <span class="comment"># the very same string object must be used on the</span></span><br><span class="line">                <span class="comment"># next call to send.  Therefore we suppress</span></span><br><span class="line">                <span class="comment"># merging the write buffer after an EWOULDBLOCK.</span></span><br><span class="line">                <span class="comment"># A cleaner solution would be to set</span></span><br><span class="line">                <span class="comment"># SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, but this is</span></span><br><span class="line">                <span class="comment"># not yet accessible from python</span></span><br><span class="line">                <span class="comment"># (http://bugs.python.org/issue8240)</span></span><br><span class="line">                self._write_buffer_frozen = <span class="literal">True</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                logging.warning(<span class="string">"Write error on %d: %s"</span>,</span><br><span class="line">                                self.socket.fileno(), e)</span><br><span class="line">                self.close()</span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self._write_buffer <span class="keyword">and</span> self._write_callback:</span><br><span class="line">        callback = self._write_callback</span><br><span class="line">        self._write_callback = <span class="literal">None</span></span><br><span class="line">        self._run_callback(callback)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-consume"><a href="#IOStream-consume" class="headerlink" title="IOStream._consume"></a>IOStream._consume</h2><p>从读缓存消费 loc 长度的数据</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_consume</span><span class="params">(self, loc)</span>:</span></span><br><span class="line">    _merge_prefix(self._read_buffer, loc)</span><br><span class="line">    <span class="keyword">return</span> self._read_buffer.popleft()</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_check_closed</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self.socket:</span><br><span class="line">        <span class="keyword">raise</span> IOError(<span class="string">"Stream is closed"</span>)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-add-io-state"><a href="#IOStream-add-io-state" class="headerlink" title="IOStream._add_io_state"></a>IOStream._add_io_state</h2><p>增加 socket 事件状态</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_add_io_state</span><span class="params">(self, state)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> self.socket <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">        <span class="comment"># connection has been closed, so there can be no future events</span></span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self._state &amp; state:</span><br><span class="line">        self._state = self._state | state</span><br><span class="line">        self.io_loop.update_handler(self.socket.fileno(), self._state)</span><br></pre></td></tr></table></figure>

<h2 id="IOStream-read-buffer-size"><a href="#IOStream-read-buffer-size" class="headerlink" title="IOStream._read_buffer_size"></a>IOStream._read_buffer_size</h2><p>获取读缓存中已有数据长度</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_read_buffer_size</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> sum(len(chunk) <span class="keyword">for</span> chunk <span class="keyword">in</span> self._read_buffer)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">SSLIOStream</span><span class="params">(IOStream)</span>:</span></span><br><span class="line">    <span class="string">"""A utility class to write to and read from a non-blocking socket.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    If the socket passed to the constructor is already connected,</span></span><br><span class="line"><span class="string">    it should be wrapped with</span></span><br><span class="line"><span class="string">        ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs)</span></span><br><span class="line"><span class="string">    before constructing the SSLIOStream.  Unconnected sockets will be</span></span><br><span class="line"><span class="string">    wrapped when IOStream.connect is finished.</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, *args, **kwargs)</span>:</span></span><br><span class="line">        <span class="string">"""Creates an SSLIOStream.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        If a dictionary is provided as keyword argument ssl_options,</span></span><br><span class="line"><span class="string">        it will be used as additional keyword arguments to ssl.wrap_socket.</span></span><br><span class="line"><span class="string">        """</span></span><br><span class="line">        self._ssl_options = kwargs.pop(<span class="string">'ssl_options'</span>, &#123;&#125;)</span><br><span class="line">        super(SSLIOStream, self).__init__(*args, **kwargs)</span><br><span class="line">        self._ssl_accepting = <span class="literal">True</span></span><br><span class="line">        self._handshake_reading = <span class="literal">False</span></span><br><span class="line">        self._handshake_writing = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">reading</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self._handshake_reading <span class="keyword">or</span> super(SSLIOStream, self).reading()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">writing</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self._handshake_writing <span class="keyword">or</span> super(SSLIOStream, self).writing()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_do_ssl_handshake</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="comment"># Based on code from test_ssl.py in the python stdlib</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self._handshake_reading = <span class="literal">False</span></span><br><span class="line">            self._handshake_writing = <span class="literal">False</span></span><br><span class="line">            self.socket.do_handshake()</span><br><span class="line">        <span class="keyword">except</span> ssl.SSLError, err:</span><br><span class="line">            <span class="keyword">if</span> err.args[<span class="number">0</span>] == ssl.SSL_ERROR_WANT_READ:</span><br><span class="line">                self._handshake_reading = <span class="literal">True</span></span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">            <span class="keyword">elif</span> err.args[<span class="number">0</span>] == ssl.SSL_ERROR_WANT_WRITE:</span><br><span class="line">                self._handshake_writing = <span class="literal">True</span></span><br><span class="line">                <span class="keyword">return</span></span><br><span class="line">            <span class="keyword">elif</span> err.args[<span class="number">0</span>] <span class="keyword">in</span> (ssl.SSL_ERROR_EOF,</span><br><span class="line">                                 ssl.SSL_ERROR_ZERO_RETURN):</span><br><span class="line">                <span class="keyword">return</span> self.close()</span><br><span class="line">            <span class="keyword">elif</span> err.args[<span class="number">0</span>] == ssl.SSL_ERROR_SSL:</span><br><span class="line">                logging.warning(<span class="string">"SSL Error on %d: %s"</span>, self.socket.fileno(), err)</span><br><span class="line">                <span class="keyword">return</span> self.close()</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line">        <span class="keyword">except</span> socket.error, err:</span><br><span class="line">            <span class="keyword">if</span> err.args[<span class="number">0</span>] == errno.ECONNABORTED:</span><br><span class="line">                <span class="keyword">return</span> self.close()</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            self._ssl_accepting = <span class="literal">False</span></span><br><span class="line">            super(SSLIOStream, self)._handle_connect()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_handle_read</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self._ssl_accepting:</span><br><span class="line">            self._do_ssl_handshake()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        super(SSLIOStream, self)._handle_read()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_handle_write</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> self._ssl_accepting:</span><br><span class="line">            self._do_ssl_handshake()</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        super(SSLIOStream, self)._handle_write()</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_handle_connect</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.socket = ssl.wrap_socket(self.socket,</span><br><span class="line">                                      do_handshake_on_connect=<span class="literal">False</span>,</span><br><span class="line">                                      **self._ssl_options)</span><br><span class="line">        <span class="comment"># Don't call the superclass's _handle_connect (which is responsible</span></span><br><span class="line">        <span class="comment"># for telling the application that the connection is complete)</span></span><br><span class="line">        <span class="comment"># until we've completed the SSL handshake (so certificates are</span></span><br><span class="line">        <span class="comment"># available, etc).</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">_read_from_socket</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="comment"># SSLSocket objects have both a read() and recv() method,</span></span><br><span class="line">            <span class="comment"># while regular sockets only have recv().</span></span><br><span class="line">            <span class="comment"># The recv() method blocks (at least in python 2.6) if it is</span></span><br><span class="line">            <span class="comment"># called when there is nothing to read, so we have to use</span></span><br><span class="line">            <span class="comment"># read() instead.</span></span><br><span class="line">            chunk = self.socket.read(self.read_chunk_size)</span><br><span class="line">        <span class="keyword">except</span> ssl.SSLError, e:</span><br><span class="line">            <span class="comment"># SSLError is a subclass of socket.error, so this except</span></span><br><span class="line">            <span class="comment"># block must come first.</span></span><br><span class="line">            <span class="keyword">if</span> e.args[<span class="number">0</span>] == ssl.SSL_ERROR_WANT_READ:</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="keyword">raise</span></span><br><span class="line">        <span class="keyword">except</span> socket.error, e:</span><br><span class="line">            <span class="keyword">if</span> e.args[<span class="number">0</span>] <span class="keyword">in</span> (errno.EWOULDBLOCK, errno.EAGAIN):</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="keyword">raise</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> chunk:</span><br><span class="line">            self.close()</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">        <span class="keyword">return</span> chunk</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_merge_prefix</span><span class="params">(deque, size)</span>:</span></span><br><span class="line">    <span class="string">"""Replace the first entries in a deque of strings with a single</span></span><br><span class="line"><span class="string">    string of up to size bytes.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; d = collections.deque(['abc', 'de', 'fghi', 'j'])</span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 5); print d</span></span><br><span class="line"><span class="string">    deque(['abcde', 'fghi', 'j'])</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Strings will be split as necessary to reach the desired size.</span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 7); print d</span></span><br><span class="line"><span class="string">    deque(['abcdefg', 'hi', 'j'])</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 3); print d</span></span><br><span class="line"><span class="string">    deque(['abc', 'defg', 'hi', 'j'])</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    &gt;&gt;&gt; _merge_prefix(d, 100); print d</span></span><br><span class="line"><span class="string">    deque(['abcdefghij'])</span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    prefix = []</span><br><span class="line">    remaining = size</span><br><span class="line">    <span class="keyword">while</span> deque <span class="keyword">and</span> remaining &gt; <span class="number">0</span>:</span><br><span class="line">        chunk = deque.popleft()</span><br><span class="line">        <span class="keyword">if</span> len(chunk) &gt; remaining:</span><br><span class="line">            deque.appendleft(chunk[remaining:])</span><br><span class="line">            chunk = chunk[:remaining]</span><br><span class="line">        prefix.append(chunk)</span><br><span class="line">        remaining -= len(chunk)</span><br><span class="line">    deque.appendleft(<span class="string">''</span>.join(prefix))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">doctests</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">import</span> doctest</span><br><span class="line">    <span class="keyword">return</span> doctest.DocTestSuite()</span><br></pre></td></tr></table></figure>

<h2 id="copyright"><a href="#copyright" class="headerlink" title="copyright"></a>copyright</h2><p>author：bigfish<br>copyright: <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">许可协议 知识共享署名 - 非商业性使用 4.0 国际许可协议</a></p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/8" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/8</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/11/29/python-decorators/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/11/29/python-decorators/" itemprop="url">python decorators</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-11-29T09:19:21+08:00">
                2018-11-29
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  773
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  3
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="python-decorators"><a href="#python-decorators" class="headerlink" title="python decorators"></a>python decorators</h1><h2 id="装饰器基础"><a href="#装饰器基础" class="headerlink" title="装饰器基础"></a>装饰器基础</h2><h3 id="Decorator-本质"><a href="#Decorator-本质" class="headerlink" title="Decorator 本质"></a>Decorator 本质</h3><p>@ 本质是语法糖 - Syntactic Sugar<br>使用 @decorator 来修饰某个函数 func 时：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@decorator</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure>

<p>其解释器会解释成：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">func = decorator(func)</span><br></pre></td></tr></table></figure>

<p>注意这条语句会被执行</p>
<p><strong>多重装饰器</strong></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@decorator_one</span></span><br><span class="line"><span class="meta">@decorator_two</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure>

<p>相当于：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">func = decorator_one(decorator_two(func))</span><br></pre></td></tr></table></figure>

<p><strong>带参数装饰器</strong></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@decorator(arg1, arg2)</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure>

<p>相当于：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">func = decorator(arg1,arg2)(func)</span><br></pre></td></tr></table></figure>

<h3 id="使用-args、-kwargs-给被装饰函数传递参数"><a href="#使用-args、-kwargs-给被装饰函数传递参数" class="headerlink" title="使用 *args、**kwargs 给被装饰函数传递参数"></a>使用 <code>*args、**kwargs</code> 给被装饰函数传递参数</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(func)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">wrapper_in</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line">        <span class="comment"># args是一个数组，kwargs一个字典</span></span><br><span class="line">        print(<span class="string">"%s is running"</span> % func.__name__)</span><br><span class="line">        <span class="keyword">return</span> func(*args, **kwargs)</span><br><span class="line">    <span class="keyword">return</span> wrapper_in</span><br><span class="line"></span><br><span class="line"><span class="meta">@wrapper</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func</span><span class="params">(parameter1, parameter2, key1=<span class="number">1</span>)</span>:</span></span><br><span class="line">    print(<span class="string">"call func with &#123;&#125; &#123;&#125; &#123;&#125;"</span>.format(parameter1, parameter2, key1))</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">func(<span class="string">"haha"</span>, <span class="literal">None</span>, key1=<span class="number">2</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># func is running</span></span><br><span class="line"><span class="comment"># call func with haha None 2</span></span><br></pre></td></tr></table></figure>

<h3 id="带参数的装饰器"><a href="#带参数的装饰器" class="headerlink" title="带参数的装饰器"></a>带参数的装饰器</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">log</span><span class="params">(level)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">decorator</span><span class="params">(func)</span>:</span></span><br><span class="line">        <span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line">            <span class="keyword">if</span> level == <span class="string">"warn"</span>:</span><br><span class="line">                print(<span class="string">"%s with warn is running"</span> % func.__name__)</span><br><span class="line">            <span class="keyword">elif</span> level == <span class="string">"info"</span>:</span><br><span class="line">                print(<span class="string">"%s with info is running"</span> % func.__name__)</span><br><span class="line">            <span class="keyword">return</span> func(*args, **kwargs)</span><br><span class="line">        <span class="keyword">return</span> wrapper</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> decorator</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@log("warn")</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">foo</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line">    print(<span class="string">"args &#123;&#125;, kwargs&#123;&#125;"</span>.format(args, kwargs))</span><br><span class="line"></span><br><span class="line">foo(<span class="number">1</span>, <span class="number">2</span>, a = <span class="number">3</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># foo with warn is running</span></span><br><span class="line"><span class="comment"># args (1, 2), kwargs&#123;'a': 3&#125;</span></span><br></pre></td></tr></table></figure>

<p>等同于</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">foo</span><span class="params">(name=<span class="string">'foo'</span>)</span>:</span></span><br><span class="line">    print(<span class="string">"args &#123;&#125;, kwargs&#123;&#125;"</span>.format(args, kwargs))</span><br><span class="line"></span><br><span class="line">foo = log(<span class="string">"warn"</span>)(foo)</span><br></pre></td></tr></table></figure>

<h3 id="方法装饰器"><a href="#方法装饰器" class="headerlink" title="方法装饰器"></a>方法装饰器</h3><p>类方法是一个特殊的函数，它的第一个参数 self 指向类实例<br>所以我们同样可以装饰类方法</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">decorate</span><span class="params">(func)</span>:</span></span><br><span class="line">   <span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(self)</span>:</span></span><br><span class="line">       <span class="keyword">return</span> <span class="string">"&lt;p&gt;&#123;0&#125;&lt;/p&gt;"</span>.format(func(self))</span><br><span class="line">   <span class="keyword">return</span> wrapper</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.name = <span class="string">"John"</span></span><br><span class="line">        self.family = <span class="string">"Doe"</span></span><br><span class="line"></span><br><span class="line"><span class="meta">    @decorate</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">get_fullname</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.name+<span class="string">" "</span>+self.family</span><br><span class="line"></span><br><span class="line">my_person = Person()</span><br><span class="line"><span class="keyword">print</span> my_person.get_fullname()</span><br><span class="line"></span><br><span class="line"><span class="comment"># &lt;p&gt;John Doe&lt;/p&gt;</span></span><br></pre></td></tr></table></figure>

<p>上例相当于固定了 self 参数, 不太灵活<br>使用 <code>*args, **kwargs</code>传递给 wrapper 更加通用：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">pecorate</span><span class="params">(func)</span>:</span></span><br><span class="line">   <span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(*args, **kwargs)</span>:</span></span><br><span class="line">       <span class="keyword">return</span> <span class="string">"&lt;p&gt;&#123;0&#125;&lt;/p&gt;"</span>.format(func(*args, **kwargs))</span><br><span class="line">   <span class="keyword">return</span> wrapper</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.name = <span class="string">"John"</span></span><br><span class="line">        self.family = <span class="string">"Doe"</span></span><br><span class="line"></span><br><span class="line"><span class="meta">    @pecorate</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">get_fullname</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">return</span> self.name+<span class="string">" "</span>+self.family</span><br><span class="line"></span><br><span class="line">my_person = Person()</span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> my_person.get_fullname()</span><br></pre></td></tr></table></figure>

<h3 id="类装饰器"><a href="#类装饰器" class="headerlink" title="类装饰器"></a>类装饰器</h3><p>类实现 <code>__call__</code> 方法后变成可调用对象，故可以用类做装饰器</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">EntryExit</span><span class="params">(object)</span>:</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, f)</span>:</span></span><br><span class="line">        self.f = f</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__call__</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">print</span> <span class="string">"Entering"</span>, self.f.__name__</span><br><span class="line">        self.f()</span><br><span class="line">        <span class="keyword">print</span> <span class="string">"Exited"</span>, self.f.__name__</span><br><span class="line"></span><br><span class="line"><span class="meta">@EntryExit</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func1</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"inside func1()"</span></span><br><span class="line"></span><br><span class="line"><span class="meta">@EntryExit</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func2</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"inside func2()"</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func3</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> type(EntryExit(<span class="literal">None</span>))</span><br><span class="line"><span class="comment"># func1 变为类实例</span></span><br><span class="line"><span class="keyword">print</span> type(func1)</span><br><span class="line"><span class="keyword">print</span> type(EntryExit)</span><br><span class="line"><span class="comment"># func3 是普通函数</span></span><br><span class="line"><span class="keyword">print</span> type(func3)</span><br><span class="line">func1()</span><br><span class="line">func2()</span><br><span class="line"></span><br><span class="line"><span class="comment"># &lt;class '__main__.EntryExit'&gt;</span></span><br><span class="line"><span class="comment"># &lt;class '__main__.EntryExit'&gt;</span></span><br><span class="line"><span class="comment"># &lt;type 'type'&gt;</span></span><br><span class="line"><span class="comment"># &lt;type 'function'&gt;</span></span><br><span class="line"><span class="comment"># Entering func1</span></span><br><span class="line"><span class="comment"># inside func1()</span></span><br><span class="line"><span class="comment"># Exited func1</span></span><br><span class="line"><span class="comment"># Entering func2</span></span><br><span class="line"><span class="comment"># inside func2()</span></span><br><span class="line"><span class="comment"># Exited func2</span></span><br></pre></td></tr></table></figure>

<p>类装饰器</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@EntryExit</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func1</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"inside func1()"</span></span><br></pre></td></tr></table></figure>

<p>等同于</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">func1</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"inside func1()"</span></span><br><span class="line"><span class="comment"># 此处可以看出 func1 是类EntryExit的一个实例</span></span><br><span class="line">func1 = EntryExit(myfunc1)</span><br></pre></td></tr></table></figure>

<h3 id="装饰器装饰类"><a href="#装饰器装饰类" class="headerlink" title="装饰器装饰类"></a>装饰器装饰类</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">register_handles = []</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">route</span><span class="params">(url)</span>:</span></span><br><span class="line">    <span class="keyword">global</span> register_handles</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">register</span><span class="params">(handler)</span>:</span></span><br><span class="line">        register_handles.append((<span class="string">".*$"</span>, [(url, handler)]))</span><br><span class="line">        <span class="keyword">return</span> handler</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> register</span><br><span class="line"></span><br><span class="line"><span class="meta">@route("/index")</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Index</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">get</span><span class="params">(self, *args, **kwargs)</span>:</span></span><br><span class="line">        print(<span class="string">"hi"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Index 仍然为原来定义的类实例</span></span><br><span class="line"><span class="comment"># 相当于在定义类的同时调用装饰器函数 route， 将该类注册到全局路由 register_handles</span></span><br><span class="line"><span class="meta">@route("/main")</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">get</span><span class="params">(self, *args, **kwargs)</span>:</span></span><br><span class="line">        print(<span class="string">"hi"</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> (register_handles)</span><br><span class="line"></span><br><span class="line">print(type(Index))</span><br><span class="line"></span><br><span class="line"><span class="comment"># [('.*$', [('/index', &lt;class __main__.Index at 0x0000000002A49828&gt;)]), ('.*$', [('/main', &lt;class __main__.Main at 0x0000000002FBABE8&gt;)])]</span></span><br><span class="line"><span class="comment"># &lt;type 'classobj'&gt;</span></span><br></pre></td></tr></table></figure>

<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@route("/index")</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Index</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">get</span><span class="params">(self, *args, **kwargs)</span>:</span></span><br><span class="line">        print(<span class="string">"hi"</span>)</span><br></pre></td></tr></table></figure>

<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Index = route(<span class="string">"/index"</span>)(Index)</span><br><span class="line"><span class="comment"># register 返回传入的 handler,故 Index 仍然为类对象</span></span><br></pre></td></tr></table></figure>

<h2 id="functools"><a href="#functools" class="headerlink" title="functools"></a>functools</h2><p>上述装饰器实现有个问题，就是被装饰函数的属性被改变</p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/7" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/7</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/11/16/python-setup.py--qian-xi/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/11/16/python-setup.py--qian-xi/" itemprop="url">python setup.py 浅析</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-11-16T14:02:43+08:00">
                2018-11-16
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  2.1k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  10
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="python-setup-py-浅析"><a href="#python-setup-py-浅析" class="headerlink" title="python setup.py 浅析"></a>python setup.py 浅析</h1><h2 id="setuptools-setup-参数说明"><a href="#setuptools-setup-参数说明" class="headerlink" title="setuptools.setup() 参数说明"></a>setuptools.setup() 参数说明</h2><h3 id="packages"><a href="#packages" class="headerlink" title="packages"></a>packages</h3><p>对于所有 packages 列表里提到的纯 Python 模块做处理<br>需要在 setup 脚本里有一个包名到目录的映射。<br>默认对于 setup 脚本所在目录下同名的目录即视为包所在目录。<br>当你在 setup 脚本中写入 packages = [‘foo’] 时， setup 脚本的同级目录下可以找到 <code>foo/__init__.py</code>。如果没有找到对应文件，disutils 不会直接报错，而是给出一个告警然后继续进行有问题的打包流程。</p>
<h3 id="package-dir"><a href="#package-dir" class="headerlink" title="package_dir"></a>package_dir</h3><p>阐明包名到目录的映射，见 packages</p>
<pre><code>package_dir = {&apos;&apos;: &apos;lib&apos;}</code></pre><p>键: 代表了包的名字，空的包名则代表 root package(不在任何包中的顶层包)。<br>值: 代表了对于 setup 脚本所在目录的相对路径.</p>
<pre><code>packages = [&apos;foo&apos;]
package_dir = {&apos;&apos;: &apos;lib&apos;}</code></pre><p>指明包位于 lib/foo/, <code>lib/foo/__init__.py</code> 这个文件存在</p>
<p>另一种方法则是直接将 foo 这个包的内容全部放入 lib 而不是在 lib 下建一个 foo 目录</p>
<pre><code>package_dir = {&apos;foo&apos;: &apos;lib&apos;}</code></pre><p>一个在 package_dir 字典中的 package: dir 映射会对当前包下的所有包都生效， 所以 foo.bar 会自动生效. 在这个例子当中， <code>packages = [&#39;foo&#39;, &#39;foo.bar&#39;]</code> 告诉 distutils 去寻找 <code>lib/__init__.py</code> 和 <code>lib/bar/__init__.py</code>.</p>
<h3 id="py-modules"><a href="#py-modules" class="headerlink" title="py_modules"></a>py_modules</h3><p>对于一个相对较小的模块的发布，你可能更想要列出所有模块而不是列出所有的包，尤其是对于那种根目录下就是一个简单模块的类型.<br>这描述了两个包，一个在根目录下，另一个则在 pkg 目录下。<br>默认的 “包：目录” 映射关系表明你可以在 setup 脚本所在的路径下找到 mod1.py 和 pkg/mod2.py。<br>当然，你也可以用 package_dir 选项重写这层映射关系就是了。</p>
<h3 id="find-packages"><a href="#find-packages" class="headerlink" title="find_packages"></a>find_packages</h3><p>packages=find_packages(exclude=(‘tests’, ‘robot_server.scripts’)),<br>exclude 里面是包名，而非路径</p>
<h3 id="include-package-data"><a href="#include-package-data" class="headerlink" title="include_package_data"></a>include_package_data</h3><p>引入包内的非 Python 文件<br>include_package_data 需要配合 MANIFEST.in 一起使用</p>
<p>MANIFEST.in:</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">include myapp/scripts/start.py</span><br><span class="line">recursive-include myapp/static *</span><br></pre></td></tr></table></figure>

<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">setup(</span><br><span class="line">    name=<span class="string">'MyApp'</span>,         <span class="comment"># 应用名</span></span><br><span class="line">    version=<span class="string">'1.0'</span>,        <span class="comment"># 版本号</span></span><br><span class="line">    packages=[<span class="string">'myapp'</span>],   <span class="comment"># 包括在安装包内的Python包</span></span><br><span class="line">    include_package_data=<span class="literal">True</span>    <span class="comment"># 启用清单文件MANIFEST.in</span></span><br><span class="line">)</span><br></pre></td></tr></table></figure>

<p>注意，此处引入或者排除的文件必须是 package 内的文件</p>
<pre><code>setup-demo/
  ├ mydata.data      # 数据文件
  ├ setup.py         # 安装文件
  ├ MANIFEST.in      # 清单文件
  └ myapp/           # 源代码
      ├ static/      # 静态文件目录
      ├ __init__.py
      ...</code></pre><p>在 MANIFEST.in 引入 include mydata.data 将不起作用</p>
<h3 id="exclude-package-date"><a href="#exclude-package-date" class="headerlink" title="exclude_package_date"></a>exclude_package_date</h3><p>排除一部分包文件<br>{‘myapp’:[‘.gitignore]}，就表明只排除 myapp 包下的所有. gitignore 文件。</p>
<h3 id="data-files"><a href="#data-files" class="headerlink" title="data_files"></a>data_files</h3><p>指定其他的一些文件（如配置文件）</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">data_files=[(<span class="string">'bitmaps'</span>, [<span class="string">'bm/b1.gif'</span>, <span class="string">'bm/b2.gif'</span>]),</span><br><span class="line">            (<span class="string">'config'</span>, [<span class="string">'cfg/data.cfg'</span>]),</span><br><span class="line">            (<span class="string">'/etc/init.d'</span>, [<span class="string">'init-script'</span>])]</span><br></pre></td></tr></table></figure>

<p>规定了哪些文件被安装到哪些目录中。<br>如果目录名是相对路径 (比如 bitmaps)，则是相对于 sys.prefix(/usr) 或 sys.exec_prefix 的路径。<br>否则安装到绝对路径 (比如 /etc/init.d)。</p>
<h3 id="cmdclass"><a href="#cmdclass" class="headerlink" title="cmdclass"></a>cmdclass</h3><p>定制化命令，通过继承 setuptools.command 下的命令类来进行定制化</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UploadCommand</span><span class="params">(Command)</span>:</span></span><br><span class="line">    <span class="string">"""Support setup.py upload."""</span></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self.status(<span class="string">'Removing previous builds…'</span>)</span><br><span class="line">            rmtree(os.path.join(here, <span class="string">'dist'</span>))</span><br><span class="line">        <span class="keyword">except</span> OSError:</span><br><span class="line">            <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">        self.status(<span class="string">'Building Source and Wheel (universal) distribution…'</span>)</span><br><span class="line">        os.system(<span class="string">'&#123;0&#125; setup.py sdist bdist_wheel --universal'</span>.format(sys.executable))</span><br><span class="line"></span><br><span class="line">        self.status(<span class="string">'Uploading the package to PyPI via Twine…'</span>)</span><br><span class="line">        os.system(<span class="string">'twine upload dist/*'</span>)</span><br><span class="line"></span><br><span class="line">        self.status(<span class="string">'Pushing git tags…'</span>)</span><br><span class="line">        os.system(<span class="string">'git tag v&#123;0&#125;'</span>.format(about[<span class="string">'__version__'</span>]))</span><br><span class="line">        os.system(<span class="string">'git push --tags'</span>)</span><br><span class="line"></span><br><span class="line">        sys.exit()</span><br><span class="line"></span><br><span class="line">setup(</span><br><span class="line">    ...</span><br><span class="line">    <span class="comment"># $ setup.py publish support.</span></span><br><span class="line">    cmdclass=&#123;</span><br><span class="line">        <span class="string">'upload'</span>: UploadCommand,</span><br><span class="line">    &#125;,</span><br><span class="line">)</span><br></pre></td></tr></table></figure>

<p>这样可以通过 <code>python setup.py upload</code> 运行打包上传代码</p>
<h3 id="install-requires"><a href="#install-requires" class="headerlink" title="install_requires"></a>install_requires</h3><p>安装这个包所需要的依赖，列表</p>
<h3 id="tests-require"><a href="#tests-require" class="headerlink" title="tests_require"></a>tests_require</h3><p>与 install_requires 作用相似，单元测试时所需要的依赖</p>
<h2 id="虚拟运行环境下安装包"><a href="#虚拟运行环境下安装包" class="headerlink" title="虚拟运行环境下安装包"></a>虚拟运行环境下安装包</h2><p>以 <a href="https://github.com/kennethreitz/legit" target="_blank" rel="noopener">legit</a> 为例</p>
<ul>
<li><p>下载 lgit 源码<br><code>git clone https://github.com/kennethreitz/legit.git</code></p>
</li>
<li><p>创建虚拟运行环境<br><code>virtualenv --no-site-packages venv</code><br>运行环境目录结构为：</p>
<pre><code>venv/
├── bin
├── include
├── lib
├── local
└── pip-selfcheck.json</code></pre></li>
<li><p>打包工程<br><code>python3 setup.py sdist bdist_wheel</code></p>
<pre><code>.
├── AUTHORS
├── build
│   ├── bdist.linux-x86_64
│   └── lib.linux-x86_64-2.7
├── dist
│   ├── legit-1.0.1-py2.py3-none-any.whl
│   └── legit-1.0.1.tar.gz</code></pre><p>在 dist 下生成了安装包</p>
</li>
<li><p>进入虚拟环境<br><code>source venv/bin/activate</code></p>
</li>
<li><p>安装包<br> <code>pip install ./dist/legit-1.0.1.tar.gz</code></p>
<pre><code>Successfully built legit args clint
Installing collected packages: appdirs, args, click, lint, colorama, crayons, smmap2, gitdb2, GitPython, ix, pyparsing, packaging, legit
Successfully installed GitPython-2.1.8 appdirs-1.4.3 rgs-0.1.0 click-6.7 clint-0.5.1 colorama-0.4.0 rayons-0.1.2 gitdb2-2.0.3 legit-1.0.1 packaging-17.1 yparsing-2.2.0 six-1.11.0 smmap2-2.0.3</code></pre></li>
</ul>
<h2 id="安装过程分析"><a href="#安装过程分析" class="headerlink" title="安装过程分析"></a>安装过程分析</h2><p><code>venv/lib/python2.7/site-packages/</code> 下安装了 legit 及依赖包</p>
<pre><code>legit/venv/lib/python2.7/site-packages$ tree -L 1

.
├── appdirs-1.4.3.dist-info
├── appdirs.py
├── appdirs.pyc
├── args-0.1.0.dist-info
├── args.py
├── args.pyc
├── click
├── click-6.7.dist-info
├── clint
├── clint-0.5.1.dist-info
├── colorama
├── colorama-0.4.0.dist-info
├── crayons-0.1.2.dist-info
├── crayons.py
├── crayons.pyc
├── easy_install.py
├── easy_install.pyc
├── git
├── gitdb
├── gitdb2-2.0.3.dist-info
├── GitPython-2.1.8.dist-info
├── legit
├── legit-1.0.1.dist-info
├── packaging
├── packaging-17.1.dist-info
├── pip
├── pip-18.1.dist-info
├── pkg_resources
├── pyparsing-2.2.0.dist-info
├── pyparsing.py
├── pyparsing.pyc
├── setuptools
├── setuptools-40.6.2.dist-info
├── six-1.11.0.dist-info
├── six.py
├── six.pyc
├── smmap
├── smmap2-2.0.3.dist-info
├── wheel
└── wheel-0.32.2.dist-info</code></pre><p><code>venv/bin</code> 下新增可执行文件 legit, 内容为</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/home/turtlebot/learn/python/legit/venv/bin/python</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">import</span> re</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> legit.cli <span class="keyword">import</span> cli</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">    sys.argv[<span class="number">0</span>] = re.sub(<span class="string">r'(-script\.pyw?|\.exe)?$'</span>, <span class="string">''</span>, sys.argv[<span class="number">0</span>])</span><br><span class="line">    sys.exit(cli())</span><br></pre></td></tr></table></figure>

<p>此时，可以直接运行</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&gt;&gt;&gt; legit</span><br></pre></td></tr></table></figure>

<h2 id="setup-py-分析"><a href="#setup-py-分析" class="headerlink" title="setup.py 分析"></a>setup.py 分析</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">from</span> codecs <span class="keyword">import</span> open  <span class="comment"># To use a consistent encoding</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> setuptools <span class="keyword">import</span> setup  <span class="comment"># Always prefer setuptools over distutils</span></span><br><span class="line"></span><br><span class="line">APP_NAME = <span class="string">'legit'</span></span><br><span class="line">APP_SCRIPT = <span class="string">'./legit_r'</span></span><br><span class="line">VERSION = <span class="string">'1.0.1'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Grab requirements.</span></span><br><span class="line"><span class="keyword">with</span> open(<span class="string">'reqs.txt'</span>) <span class="keyword">as</span> f:</span><br><span class="line">    required = f.readlines()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">settings = dict()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Publish Helper.</span></span><br><span class="line"><span class="keyword">if</span> sys.argv[<span class="number">-1</span>] == <span class="string">'publish'</span>:</span><br><span class="line">    os.system(<span class="string">'python setup.py sdist bdist_wheel upload'</span>)</span><br><span class="line">    sys.exit()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> sys.argv[<span class="number">-1</span>] == <span class="string">'build_manpage'</span>:</span><br><span class="line">    os.system(<span class="string">'rst2man.py README.rst &gt; extra/man/legit.1'</span>)</span><br><span class="line">    sys.exit()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Build Helper.</span></span><br><span class="line"><span class="keyword">if</span> sys.argv[<span class="number">-1</span>] == <span class="string">'build'</span>:</span><br><span class="line">    <span class="keyword">import</span> py2exe  <span class="comment"># noqa</span></span><br><span class="line">    sys.argv.append(<span class="string">'py2exe'</span>)</span><br><span class="line"></span><br><span class="line">    settings.update(</span><br><span class="line">        console=[&#123;<span class="string">'script'</span>: APP_SCRIPT&#125;],</span><br><span class="line">        zipfile=<span class="literal">None</span>,</span><br><span class="line">        options=&#123;</span><br><span class="line">            <span class="string">'py2exe'</span>: &#123;</span><br><span class="line">                <span class="string">'compressed'</span>: <span class="number">1</span>,</span><br><span class="line">                <span class="string">'optimize'</span>: <span class="number">0</span>,</span><br><span class="line">                <span class="string">'bundle_files'</span>: <span class="number">1</span>&#125;&#125;)</span><br><span class="line"></span><br><span class="line">settings.update(</span><br><span class="line">    name=APP_NAME,</span><br><span class="line">    version=VERSION,</span><br><span class="line">    description=<span class="string">'Git for Humans.'</span>,</span><br><span class="line">    long_description=open(<span class="string">'README.rst'</span>).read(),</span><br><span class="line">    author=<span class="string">'Kenneth Reitz'</span>,</span><br><span class="line">    author_email=<span class="string">'me@kennethreitz.com'</span>,</span><br><span class="line">    url=<span class="string">'https://github.com/kennethreitz/legit'</span>,</span><br><span class="line">    packages=[<span class="string">'legit'</span>],</span><br><span class="line">    install_requires=required,</span><br><span class="line">    license=<span class="string">'BSD'</span>,</span><br><span class="line">    classifiers=[</span><br><span class="line">        <span class="string">'Development Status :: 5 - Production/Stable'</span>,</span><br><span class="line">        <span class="string">'Intended Audience :: Developers'</span>,</span><br><span class="line">        <span class="string">'Natural Language :: English'</span>,</span><br><span class="line">        <span class="string">'License :: OSI Approved :: BSD License'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 2'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 2.7'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 3'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 3.4'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 3.5'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 3.6'</span>,</span><br><span class="line">    ],</span><br><span class="line">    entry_points=&#123;</span><br><span class="line">        <span class="string">'console_scripts'</span>: [</span><br><span class="line">            <span class="string">'legit = legit.cli:cli'</span>,</span><br><span class="line">        ],</span><br><span class="line">    &#125;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">setup(**settings)</span><br></pre></td></tr></table></figure>

<ul>
<li>packages=[‘legit’] 引入 legit 目录下的所有默认引入文件</li>
<li>install_requires=required 指明安装时需要额外安装的第三方库</li>
<li><code>&#39;console_scripts&#39;: [&#39;legit = legit.cli:cli&#39;,]</code> 生成可执行控制台程序，程序名为 legit, 运行 legit.cli 中的 cli() 函数。最终会在 bin/ 下生成 legit 可执行 py 文件，调用制定的函数</li>
</ul>
<h2 id="setup-py-实例分析"><a href="#setup-py-实例分析" class="headerlink" title="setup.py 实例分析"></a>setup.py 实例分析</h2><p><a href="https://github.com/kennethreitz/setup.py" target="_blank" rel="noopener">kennethreitz/setup.py</a></p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python</span></span><br><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Note: To use the 'upload' functionality of this file, you must:</span></span><br><span class="line"><span class="comment">#   $ pip install twine</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io</span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">from</span> shutil <span class="keyword">import</span> rmtree</span><br><span class="line"></span><br><span class="line"><span class="keyword">from</span> setuptools <span class="keyword">import</span> find_packages, setup, Command</span><br><span class="line"></span><br><span class="line"><span class="comment"># Package meta-data.</span></span><br><span class="line">NAME = <span class="string">'mypackage'</span></span><br><span class="line">DESCRIPTION = <span class="string">'My short description for my project.'</span></span><br><span class="line">URL = <span class="string">'https://github.com/me/myproject'</span></span><br><span class="line">EMAIL = <span class="string">'me@example.com'</span></span><br><span class="line">AUTHOR = <span class="string">'Awesome Soul'</span></span><br><span class="line">REQUIRES_PYTHON = <span class="string">'&gt;=3.6.0'</span></span><br><span class="line">VERSION = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># What packages are required for this module to be executed?</span></span><br><span class="line">REQUIRED = [</span><br><span class="line">    <span class="comment"># 'requests', 'maya', 'records',</span></span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="comment"># What packages are optional?</span></span><br><span class="line">EXTRAS = &#123;</span><br><span class="line">    <span class="comment"># 'fancy feature': ['django'],</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># The rest you shouldn't have to touch too much :)</span></span><br><span class="line"><span class="comment"># ------------------------------------------------</span></span><br><span class="line"><span class="comment"># Except, perhaps the License and Trove Classifiers!</span></span><br><span class="line"><span class="comment"># If you do change the License, remember to change the Trove Classifier for that!</span></span><br><span class="line"></span><br><span class="line">here = os.path.abspath(os.path.dirname(__file__))</span><br><span class="line"></span><br><span class="line"><span class="comment"># Import the README and use it as the long-description.</span></span><br><span class="line"><span class="comment"># Note: this will only work if 'README.md' is present in your MANIFEST.in file!</span></span><br><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="keyword">with</span> io.open(os.path.join(here, <span class="string">'README.md'</span>), encoding=<span class="string">'utf-8'</span>) <span class="keyword">as</span> f:</span><br><span class="line">        long_description = <span class="string">'\n'</span> + f.read()</span><br><span class="line"><span class="keyword">except</span> FileNotFoundError:</span><br><span class="line">    long_description = DESCRIPTION</span><br><span class="line"></span><br><span class="line"><span class="comment"># Load the package's __version__.py module as a dictionary.</span></span><br><span class="line">about = &#123;&#125;</span><br><span class="line"><span class="keyword">if</span> <span class="keyword">not</span> VERSION:</span><br><span class="line">    <span class="keyword">with</span> open(os.path.join(here, NAME, <span class="string">'__version__.py'</span>)) <span class="keyword">as</span> f:</span><br><span class="line">        exec(f.read(), about)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line">    about[<span class="string">'__version__'</span>] = VERSION</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">UploadCommand</span><span class="params">(Command)</span>:</span></span><br><span class="line">    <span class="string">"""Support setup.py upload."""</span></span><br><span class="line"></span><br><span class="line">    description = <span class="string">'Build and publish the package.'</span></span><br><span class="line">    user_options = []</span><br><span class="line"></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">status</span><span class="params">(s)</span>:</span></span><br><span class="line">        <span class="string">"""Prints things in bold."""</span></span><br><span class="line">        print(<span class="string">'\033[1m&#123;0&#125;\033[0m'</span>.format(s))</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">initialize_options</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">finalize_options</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self.status(<span class="string">'Removing previous builds…'</span>)</span><br><span class="line">            rmtree(os.path.join(here, <span class="string">'dist'</span>))</span><br><span class="line">        <span class="keyword">except</span> OSError:</span><br><span class="line">            <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">        self.status(<span class="string">'Building Source and Wheel (universal) distribution…'</span>)</span><br><span class="line">        os.system(<span class="string">'&#123;0&#125; setup.py sdist bdist_wheel --universal'</span>.format(sys.executable))</span><br><span class="line"></span><br><span class="line">        self.status(<span class="string">'Uploading the package to PyPI via Twine…'</span>)</span><br><span class="line">        os.system(<span class="string">'twine upload dist/*'</span>)</span><br><span class="line"></span><br><span class="line">        self.status(<span class="string">'Pushing git tags…'</span>)</span><br><span class="line">        os.system(<span class="string">'git tag v&#123;0&#125;'</span>.format(about[<span class="string">'__version__'</span>]))</span><br><span class="line">        os.system(<span class="string">'git push --tags'</span>)</span><br><span class="line"></span><br><span class="line">        sys.exit()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># Where the magic happens:</span></span><br><span class="line">setup(</span><br><span class="line">    name=NAME,</span><br><span class="line">    version=about[<span class="string">'__version__'</span>],</span><br><span class="line">    description=DESCRIPTION,</span><br><span class="line">    long_description=long_description,</span><br><span class="line">    long_description_content_type=<span class="string">'text/markdown'</span>,</span><br><span class="line">    author=AUTHOR,</span><br><span class="line">    author_email=EMAIL,</span><br><span class="line">    python_requires=REQUIRES_PYTHON,</span><br><span class="line">    url=URL,</span><br><span class="line">    packages=find_packages(exclude=(<span class="string">'tests'</span>,)),</span><br><span class="line">    <span class="comment"># If your package is a single module, use this instead of 'packages':</span></span><br><span class="line">    <span class="comment"># py_modules=['mypackage'],</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># entry_points=&#123;</span></span><br><span class="line">    <span class="comment">#     'console_scripts': ['mycli=mymodule:cli'],</span></span><br><span class="line">    <span class="comment"># &#125;,</span></span><br><span class="line">    install_requires=REQUIRED,</span><br><span class="line">    extras_require=EXTRAS,</span><br><span class="line">    include_package_data=<span class="literal">True</span>,</span><br><span class="line">    license=<span class="string">'MIT'</span>,</span><br><span class="line">    classifiers=[</span><br><span class="line">        <span class="comment"># Trove classifiers</span></span><br><span class="line">        <span class="comment"># Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers</span></span><br><span class="line">        <span class="string">'License :: OSI Approved :: MIT License'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 3'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: 3.6'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: Implementation :: CPython'</span>,</span><br><span class="line">        <span class="string">'Programming Language :: Python :: Implementation :: PyPy'</span></span><br><span class="line">    ],</span><br><span class="line">    <span class="comment"># $ setup.py publish support.</span></span><br><span class="line">    cmdclass=&#123;</span><br><span class="line">        <span class="string">'upload'</span>: UploadCommand,</span><br><span class="line">    &#125;,</span><br><span class="line">)</span><br></pre></td></tr></table></figure>


<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/6" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/6</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/11/15/python--duo-xian-cheng-bian-cheng/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/11/15/python--duo-xian-cheng-bian-cheng/" itemprop="url">python 多线程编程</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-11-15T13:41:30+08:00">
                2018-11-15
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  554
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  2
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="python-多线程编程"><a href="#python-多线程编程" class="headerlink" title="python 多线程编程"></a>python 多线程编程</h1><h2 id="使用回调方式"><a href="#使用回调方式" class="headerlink" title="使用回调方式"></a>使用回调方式</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> time</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">countdown</span><span class="params">(n)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> n &gt; <span class="number">0</span>:</span><br><span class="line">        print(<span class="string">'T-minus'</span>, n)</span><br><span class="line">        n -= <span class="number">1</span></span><br><span class="line">        time.sleep(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># Create and launch a thread</span></span><br><span class="line"><span class="keyword">from</span> threading <span class="keyword">import</span> Thread</span><br><span class="line">t = Thread(target=countdown, args=(<span class="number">10</span>,))</span><br><span class="line">t.start()</span><br></pre></td></tr></table></figure>

<h2 id="使用继承方式"><a href="#使用继承方式" class="headerlink" title="使用继承方式"></a>使用继承方式</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> threading <span class="keyword">import</span> Thread</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CountdownTask</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._running = <span class="literal">True</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">terminate</span><span class="params">(self)</span>:</span></span><br><span class="line">        self._running = <span class="literal">False</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self, n)</span>:</span></span><br><span class="line">        <span class="keyword">while</span> self._running <span class="keyword">and</span> n &gt; <span class="number">0</span>:</span><br><span class="line">            print(<span class="string">'T-minus'</span>, n)</span><br><span class="line">            n -= <span class="number">1</span></span><br><span class="line">            time.sleep(<span class="number">5</span>)</span><br><span class="line"></span><br><span class="line">c = CountdownTask()</span><br><span class="line">t = Thread(target=c.run, args=(<span class="number">10</span>,))</span><br><span class="line">t.start()</span><br><span class="line">c.terminate() <span class="comment"># Signal termination</span></span><br><span class="line">t.join()      <span class="comment"># Wait for actual termination (if needed)</span></span><br></pre></td></tr></table></figure>

<p>注意使用变量 <code>self._running</code> 退出线程的方式</p>
<h2 id="使用-Queue-进行线程间通信"><a href="#使用-Queue-进行线程间通信" class="headerlink" title="使用 Queue 进行线程间通信"></a>使用 Queue 进行线程间通信</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Queue</span><br><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"><span class="keyword">import</span> time</span><br><span class="line"></span><br><span class="line">task_queue = Queue.Queue()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ThreadTest</span><span class="params">(threading.Thread)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, queue)</span>:</span></span><br><span class="line">        threading.Thread.__init__(self)</span><br><span class="line">        self.queue = queue</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">            msg = self.queue.get()</span><br><span class="line">            print(msg)</span><br><span class="line">            time.sleep(<span class="number">0.1</span>)</span><br><span class="line">            self.queue.task_done()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    start = time.time()</span><br><span class="line">    <span class="comment"># populate queue with data</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">100</span>):</span><br><span class="line">        task_queue.put(<span class="string">"message"</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># spawn a pool of threads, and pass them queue instance</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(<span class="number">5</span>):</span><br><span class="line">        t = ThreadTest(task_queue)</span><br><span class="line">        t.setDaemon(<span class="literal">True</span>)</span><br><span class="line">        t.start()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># wait on the queue until everything has been processed</span></span><br><span class="line">    task_queue.join()</span><br><span class="line">    <span class="keyword">print</span> <span class="string">"Elapsed Time: &#123;&#125;"</span>.format(time.time() - start)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line">    main()</span><br></pre></td></tr></table></figure>

<p>setDaemon 设置为 True, run 函数中不需要退出，主线程结束后所有子线程退出<br>如果 setDaemon 设置为 False, 则改为</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> <span class="keyword">not</span> self.queue.empty():</span><br><span class="line">        msg = self.queue.get()</span><br><span class="line">        print(msg)</span><br><span class="line">        time.sleep(<span class="number">0.1</span>)</span><br><span class="line">        self.queue.task_done()</span><br></pre></td></tr></table></figure>

<p>并且在主函数结束前 join 所有线程</p>
<h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a><strong>注意</strong></h3><ul>
<li><p>向队列中添加数据项时并不会复制此数据项，线程间通信实际上是在线程间传递对象引用。如果你担心对象的共享状态，那你最好只传递不可修改的数据结构（如：整型、字符串或者元组）或者一个对象的深拷贝。</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> queue <span class="keyword">import</span> Queue</span><br><span class="line"><span class="keyword">from</span> threading <span class="keyword">import</span> Thread</span><br><span class="line"><span class="keyword">import</span> copy</span><br><span class="line"></span><br><span class="line"><span class="comment"># A thread that produces data</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">producer</span><span class="params">(out_q)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="comment"># Produce some data</span></span><br><span class="line">        ...</span><br><span class="line">        out_q.put(copy.deepcopy(data))</span><br><span class="line"></span><br><span class="line"><span class="comment"># A thread that consumes data</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">consumer</span><span class="params">(in_q)</span>:</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="comment"># Get some data</span></span><br><span class="line">        data = in_q.get()</span><br><span class="line">        <span class="comment"># Process the data</span></span><br><span class="line">        ...</span><br></pre></td></tr></table></figure>
</li>
<li><p>q.qsize() ， q.full() ， q.empty() 等实用方法可以获取一个队列的当前大小和状态。但要注意，这些方法都不是线程安全的。可能你对一个队列使用 empty() 判断出这个队列为空，但同时另外一个线程可能已经向这个队列中插入一个数据项。</p>
</li>
</ul>
<h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul>
<li><p><a href="https://python3-cookbook.readthedocs.io/zh_CN/latest/c12/p01_start_stop_thread.html" target="_blank" rel="noopener"><strong><em>python3-cookbook</em></strong> Chapter 12 ‘Concurrency-Starting and Stopping Threads’</a></p>
</li>
<li><p><a href="https://www.ibm.com/developerworks/aix/library/au-threadingpython/" target="_blank" rel="noopener"><strong><em>Practical threaded programming with Python</em></strong></a></p>
</li>
</ul>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/5" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/5</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/11/13/thread-local-in-python/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/11/13/thread-local-in-python/" itemprop="url">thread local in python</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-11-13T11:50:25+08:00">
                2018-11-13
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  457
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  2
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <!-- TOC -->

<ul>
<li><a href="#thread-local-in-python">thread local in python</a><ul>
<li><a href="#%E7%BA%BF%E7%A8%8B%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F">线程局部变量</a></li>
<li><a href="#%E4%B8%BB%E7%BA%BF%E7%A8%8B%E4%B9%9F%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F">主线程也有自己的线程局部变量</a></li>
<li><a href="#%E7%BB%A7%E6%89%BF-threadinglocal">继承 threading.local</a></li>
<li><a href="#%E5%BA%94%E7%94%A8%E5%AE%9E%E4%BE%8B">应用实例</a></li>
</ul>
</li>
</ul>
<!-- /TOC -->

<h1 id="thread-local-in-python"><a href="#thread-local-in-python" class="headerlink" title="thread local in python"></a>thread local in python</h1><p>参考 <a href="http://slinkp.com/python-thread-locals-20171201.html" target="_blank" rel="noopener">Thread Locals in Python: Mostly easy</a></p>
<h2 id="线程局部变量"><a href="#线程局部变量" class="headerlink" title="线程局部变量"></a>线程局部变量</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"></span><br><span class="line">mydata = threading.local()</span><br><span class="line">mydata.x = <span class="string">'hello'</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Worker</span><span class="params">(threading.Thread)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">        mydata.x = self.name</span><br><span class="line">        <span class="keyword">print</span> mydata.x</span><br><span class="line"></span><br><span class="line">w1, w2 = Worker(), Worker()</span><br><span class="line">w1.start(); w2.start(); w1.join(); w1.join()</span><br></pre></td></tr></table></figure>

<pre><code>Thread-1
Thread-2</code></pre><p>各线程独享自己的变量，但是使用全局变量 mydata</p>
<h2 id="主线程也有自己的线程局部变量"><a href="#主线程也有自己的线程局部变量" class="headerlink" title="主线程也有自己的线程局部变量"></a>主线程也有自己的线程局部变量</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"></span><br><span class="line">mydata = threading.local()</span><br><span class="line">mydata.x = &#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Worker</span><span class="params">(threading.Thread)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">        mydata.x[<span class="string">'message'</span>] = self.name</span><br><span class="line">        <span class="keyword">print</span> mydata.x[<span class="string">'message'</span>]</span><br><span class="line">w1, w2 = Worker(), Worker()</span><br><span class="line">w1.start(); w2.start(); w1.join(); w2.join()</span><br></pre></td></tr></table></figure>

<pre><code>Exception in thread Thread-1:
Traceback (most recent call last):
  File &quot;C:\Python27\lib\threading.py&quot;, line 801, in __bootstrap_inner
    self.run()
  File &quot;E:/learn/python/test/thread_local.py&quot;, line 15, in run
    mydata.x[&apos;message&apos;] = self.name
AttributeError: &apos;thread._local&apos; object has no attribute &apos;x&apos;

Exception in thread Thread-2:
Traceback (most recent call last):
  File &quot;C:\Python27\lib\threading.py&quot;, line 801, in __bootstrap_inner
    self.run()
  File &quot;E:/learn/python/test/thread_local.py&quot;, line 15, in run
    mydata.x[&apos;message&apos;] = self.name
AttributeError: &apos;thread._local&apos; object has no attribute &apos;x&apos;</code></pre><p>线程 w1,w2 没有 x 属性，子线程与主线程拥有各自的变量</p>
<h2 id="继承-threading-local"><a href="#继承-threading-local" class="headerlink" title="继承 threading.local"></a>继承 threading.local</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> threading</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyData</span><span class="params">(threading.local)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self)</span>:</span></span><br><span class="line">        self.x = &#123;&#125;</span><br><span class="line"></span><br><span class="line">mydata = MyData()</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Worker</span><span class="params">(threading.Thread)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">run</span><span class="params">(self)</span>:</span></span><br><span class="line">        mydata.x[<span class="string">'message'</span>] = self.name</span><br><span class="line">        <span class="keyword">print</span> mydata.x[<span class="string">'message'</span>]</span><br><span class="line"></span><br><span class="line">w1, w2 = Worker(), Worker()</span><br><span class="line">w1.start(); w2.start(); w1.join(); w2.join()</span><br></pre></td></tr></table></figure>

<pre><code>Thread-1
Thread-2</code></pre><h2 id="应用实例"><a href="#应用实例" class="headerlink" title="应用实例"></a>应用实例</h2><p>bottle 0.4.10</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Request</span><span class="params">(threading.local)</span>:</span></span><br><span class="line">    <span class="string">""" Represents a single request using thread-local namespace. """</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">bind</span><span class="params">(self, environ)</span>:</span></span><br><span class="line">        <span class="string">""" Binds the enviroment of the current request to this request handler """</span></span><br><span class="line">        self._environ = environ</span><br><span class="line">        self._GET = <span class="literal">None</span></span><br><span class="line">        self._POST = <span class="literal">None</span></span><br><span class="line">        self._GETPOST = <span class="literal">None</span></span><br><span class="line">        self._COOKIES = <span class="literal">None</span></span><br><span class="line">        self.path = self._environ.get(<span class="string">'PATH_INFO'</span>, <span class="string">'/'</span>).strip()</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> self.path.startswith(<span class="string">'/'</span>):</span><br><span class="line">            self.path = <span class="string">'/'</span> + self.path</span><br><span class="line"></span><br><span class="line"><span class="comment">#----------------------</span></span><br><span class="line">request = Request()</span><br><span class="line"><span class="comment">#----------------------</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">WSGIHandler</span><span class="params">(environ, start_response)</span>:</span></span><br><span class="line">    <span class="string">"""The bottle WSGI-handler."""</span></span><br><span class="line">    <span class="keyword">global</span> request</span><br><span class="line">    <span class="keyword">global</span> response</span><br><span class="line">    request.bind(environ)</span><br><span class="line">    response.bind()</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        handler, args = match_url(request.path, request.method)</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> handler:</span><br><span class="line">            <span class="keyword">raise</span> HTTPError(<span class="number">404</span>, <span class="string">"Not found"</span>)</span><br><span class="line">        output = handler(**args)</span><br><span class="line">    <span class="keyword">except</span> BreakTheBottle, shard:</span><br><span class="line">        output = shard.output</span><br></pre></td></tr></table></figure>


<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/4" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/4</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/11/07/frp--pei-zhi--http%E3%80%81websocket%E3%80%81ssh--zhuan-fa/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/11/07/frp--pei-zhi--http%E3%80%81websocket%E3%80%81ssh--zhuan-fa/" itemprop="url">frp 配置 http、websocket、ssh 转发</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-11-07T14:37:56+08:00">
                2018-11-07
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  181
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  1
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="frp-配置-http、websocket、ssh-转发"><a href="#frp-配置-http、websocket、ssh-转发" class="headerlink" title="frp 配置 http、websocket、ssh 转发"></a>frp 配置 http、websocket、ssh 转发</h1><p>参考 <a href="https://github.com/fatedier/frp/issues/75" target="_blank" rel="noopener">frp#75</a></p>
<h2 id="http-不使用域名转发"><a href="#http-不使用域名转发" class="headerlink" title="http 不使用域名转发"></a>http 不使用域名转发</h2><p><code>frps.ini</code></p>
<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[common]</span></span><br><span class="line"><span class="attr">bind_port</span> = <span class="number">7000</span></span><br></pre></td></tr></table></figure>

<p><code>frpc.ini</code></p>
<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[common]</span></span><br><span class="line"><span class="attr">server_addr</span> = aaa.bbb.ccc.ddd</span><br><span class="line"><span class="attr">server_port</span> = <span class="number">7000</span></span><br><span class="line"></span><br><span class="line"><span class="section">[tcp_port]</span></span><br><span class="line"><span class="attr">type</span> = tcp</span><br><span class="line"><span class="attr">local_ip</span> = <span class="number">127.0</span>.<span class="number">0.1</span></span><br><span class="line"><span class="attr">local_port</span> = <span class="number">2333</span></span><br><span class="line"><span class="attr">remote_port</span> = <span class="number">3333</span></span><br></pre></td></tr></table></figure>

<p>在外网通过 <a href="http://aaa.bbb.ccc.ddd:3333" target="_blank" rel="noopener">http://aaa.bbb.ccc.ddd:3333</a> 访问到内网机器里的 <a href="http://127.0.0.1:2333" target="_blank" rel="noopener">http://127.0.0.1:2333</a> 了</p>
<h2 id="ssh-转发"><a href="#ssh-转发" class="headerlink" title="ssh 转发"></a>ssh 转发</h2><p><code>frpc.ini</code></p>
<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[common]</span></span><br><span class="line"><span class="attr">server_addr</span> = aaa.bbb.ccc.ddd</span><br><span class="line"><span class="attr">server_port</span> = <span class="number">7000</span></span><br><span class="line"></span><br><span class="line"><span class="section">[ssh]</span></span><br><span class="line"><span class="attr">type</span> = tcp</span><br><span class="line"><span class="attr">local_ip</span> = <span class="number">192.168</span>.<span class="number">0.1</span></span><br><span class="line"><span class="attr">local_port</span> = <span class="number">22</span></span><br><span class="line"><span class="attr">remote_port</span> = <span class="number">7022</span></span><br><span class="line"></span><br><span class="line"><span class="section">[tcp_port]</span></span><br><span class="line"><span class="attr">type</span> = tcp</span><br><span class="line"><span class="attr">local_ip</span> = <span class="number">192.168</span>.<span class="number">0.1</span></span><br><span class="line"><span class="attr">local_port</span> = <span class="number">8888</span></span><br><span class="line"><span class="attr">remote_port</span> = <span class="number">8888</span></span><br></pre></td></tr></table></figure>

<p>在外网 <code>ssh</code> 通过 <code>ssh -oPort=7022 user@aaa.bbb.ccc.ddd</code> 访问内网机器</p>
<p>在外网 <code>http</code> 通过 <a href="http://aaa.bbb.ccc.ddd:8888" target="_blank" rel="noopener">http://aaa.bbb.ccc.ddd:8888</a> 访问到内网机器里的 <a href="http://127.0.0.1:8888" target="_blank" rel="noopener">http://127.0.0.1:8888</a> 了</p>
<p>通过 <code>ws://aaa.bbb.ccc.ddd:8888</code> 访问 websocket</p>
<h2 id="运行服务"><a href="#运行服务" class="headerlink" title="运行服务"></a>运行服务</h2><p><code>nohup ./frps -c ./frps.ini &amp;</code></p>
<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/3" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/3</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/11/01/python-json--xu-lie-hua-ji-fan-xu-lie-hua/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/11/01/python-json--xu-lie-hua-ji-fan-xu-lie-hua/" itemprop="url">python json 序列化及反序列化</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-11-01T16:10:50+08:00">
                2018-11-01
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  710
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  4
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="python-json-序列化及反序列化"><a href="#python-json-序列化及反序列化" class="headerlink" title="python json 序列化及反序列化"></a>python json 序列化及反序列化</h1><!-- TOC -->

<ul>
<li><a href="#python-json-%E5%BA%8F%E5%88%97%E5%8C%96%E5%8F%8A%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96">python json 序列化及反序列化</a><ul>
<li><a href="#%E4%BD%BF%E7%94%A8namedtuple">使用<code>namedtuple</code></a></li>
<li><a href="#%E4%BD%BF%E7%94%A8objecthook">使用<code>object_hook</code></a></li>
<li><a href="#%E8%8E%B7%E5%8F%96%E5%AF%B9%E8%B1%A1%E5%B1%9E%E6%80%A7">获取对象属性</a></li>
<li><a href="#%E8%8E%B7%E5%8F%96%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B5%8C%E5%A5%97%E5%B1%9E%E6%80%A7">获取对象的嵌套属性</a></li>
</ul>
</li>
</ul>
<!-- /TOC -->

<h2 id="使用namedtuple"><a href="#使用namedtuple" class="headerlink" title="使用namedtuple"></a>使用<code>namedtuple</code></h2><p>反序列化为 namedtuple</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="keyword">from</span> collections <span class="keyword">import</span> namedtuple</span><br><span class="line"></span><br><span class="line">data = <span class="string">'&#123;"name": "John Smith", "hometown": &#123;"name": "New York", "id": 123&#125;&#125;'</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Parse JSON into an object with attributes corresponding to dict keys.</span></span><br><span class="line">x = json.loads(data, object_hook=<span class="keyword">lambda</span> d: namedtuple(<span class="string">'X'</span>, d.keys())(*d.values()))</span><br><span class="line"><span class="keyword">print</span> x.name, x.hometown.name, x.hometown.id</span><br></pre></td></tr></table></figure>

<p>序列化为 json</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">json.dumps(x._asdict())</span><br></pre></td></tr></table></figure>

<p>输出</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&#123;"hometown": ["New York", 123], "name": "John Smith"&#125;</span><br></pre></td></tr></table></figure>

<p>封装：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_json_object_hook</span><span class="params">(d)</span>:</span> <span class="keyword">return</span> namedtuple(<span class="string">'X'</span>, d.keys())(*d.values())</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">json2obj</span><span class="params">(data)</span>:</span> <span class="keyword">return</span> json.loads(data, object_hook=_json_object_hook)</span><br><span class="line"></span><br><span class="line">x = json2obj(data)</span><br></pre></td></tr></table></figure>

<p>总结：</p>
<p>序列化及反序列化都比较方便，但是 <code>namedtuple</code> 不能进行复制，不能修改</p>
<h2 id="使用object-hook"><a href="#使用object-hook" class="headerlink" title="使用object_hook"></a>使用<code>object_hook</code></h2><p>反序列化为对象</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">JSONObject</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, d)</span>:</span></span><br><span class="line">        self.__dict__ = d</span><br><span class="line"></span><br><span class="line">data = <span class="string">'&#123;"name": "John Smith", "hometown": &#123;"name": "New York", "id": 123&#125;&#125;'</span></span><br><span class="line"></span><br><span class="line">a = json.loads(data,</span><br><span class="line">               object_hook=JSONObject)</span><br><span class="line"></span><br><span class="line">a.name = <span class="string">"changed"</span></span><br><span class="line"><span class="keyword">print</span> a.name</span><br></pre></td></tr></table></figure>

<h2 id="获取对象属性"><a href="#获取对象属性" class="headerlink" title="获取对象属性"></a>获取对象属性</h2><ul>
<li>使用 <code>getattr</code></li>
</ul>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">print</span> getattr(a.hometown, <span class="string">'id'</span>, <span class="number">321</span>)</span><br><span class="line"><span class="comment"># 123</span></span><br><span class="line"><span class="keyword">print</span> getattr(a.hometown, <span class="string">'id1'</span>, <span class="number">321</span>)</span><br><span class="line"><span class="comment"># 321</span></span><br></pre></td></tr></table></figure>

<ul>
<li>使用 <code>try</code></li>
</ul>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>:</span><br><span class="line">    <span class="keyword">print</span> a.hometown.id2</span><br><span class="line"><span class="keyword">except</span> AttributeError <span class="keyword">as</span> ex:</span><br><span class="line">    <span class="keyword">print</span> ex</span><br></pre></td></tr></table></figure>

<ul>
<li>使用 <code>get</code></li>
</ul>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">x = data.get(<span class="string">'first'</span>, &#123;&#125;).get(<span class="string">'second'</span>, &#123;&#125;).get(<span class="string">'third'</span>, <span class="literal">None</span>)</span><br></pre></td></tr></table></figure>

<h2 id="获取对象的嵌套属性"><a href="#获取对象的嵌套属性" class="headerlink" title="获取对象的嵌套属性"></a>获取对象的嵌套属性</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">multi_getattr</span><span class="params">(obj, attr, default = None)</span>:</span></span><br><span class="line">    <span class="string">"""</span></span><br><span class="line"><span class="string">    Get a named attribute from an object; multi_getattr(x, 'a.b.c.d') is</span></span><br><span class="line"><span class="string">    equivalent to x.a.b.c.d. When a default argument is given, it is</span></span><br><span class="line"><span class="string">    returned when any attribute in the chain doesn't exist; without</span></span><br><span class="line"><span class="string">    it, an exception is raised when a missing attribute is encountered.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    attributes = attr.split(<span class="string">"."</span>)</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> attributes:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            obj = getattr(obj, i)</span><br><span class="line">        <span class="keyword">except</span> AttributeError:</span><br><span class="line">            <span class="keyword">if</span> default:</span><br><span class="line">                <span class="keyword">return</span> default</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                <span class="keyword">raise</span></span><br><span class="line">    <span class="keyword">return</span> obj</span><br><span class="line"></span><br><span class="line"><span class="keyword">print</span> multi_getattr(a, <span class="string">"hometown.name"</span>)</span><br><span class="line"><span class="comment"># New York</span></span><br><span class="line"><span class="keyword">print</span> multi_getattr(a, <span class="string">"hometown.name1"</span>, <span class="string">"abc"</span>)</span><br><span class="line"><span class="comment"># abc</span></span><br></pre></td></tr></table></figure>

<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># coding=utf-8</span></span><br><span class="line"><span class="keyword">from</span> __future__ <span class="keyword">import</span> unicode_literals</span><br><span class="line"><span class="keyword">import</span> collections</span><br><span class="line"><span class="keyword">import</span> operator</span><br><span class="line"></span><br><span class="line">_default_stub = object()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">deep_get</span><span class="params">(obj, path, default=_default_stub, separator=<span class="string">'.'</span>)</span>:</span></span><br><span class="line">    <span class="string">"""Gets arbitrarily nested attribute or item value.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Args:</span></span><br><span class="line"><span class="string">        obj: Object to search in.</span></span><br><span class="line"><span class="string">        path (str, hashable, iterable of hashables): Arbitrarily nested path in obj hierarchy.</span></span><br><span class="line"><span class="string">        default: Default value. When provided it is returned if the path doesn't exist.</span></span><br><span class="line"><span class="string">            Otherwise the call raises a LookupError.</span></span><br><span class="line"><span class="string">        separator: String to split path by.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Returns:</span></span><br><span class="line"><span class="string">        Value at path.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Raises:</span></span><br><span class="line"><span class="string">        LookupError: If object at path doesn't exist.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    Examples:</span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(&#123;'a': 1&#125;, 'a')</span></span><br><span class="line"><span class="string">        1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(&#123;'a': 1&#125;, 'b')</span></span><br><span class="line"><span class="string">        Traceback (most recent call last):</span></span><br><span class="line"><span class="string">            ...</span></span><br><span class="line"><span class="string">        LookupError: &#123;u'a': 1&#125; has no element at 'b'</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(['a', 'b', 'c'], -1)</span></span><br><span class="line"><span class="string">        u'c'</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(&#123;'a': [&#123;'b': [1, 2, 3]&#125;, 'some string']&#125;, 'a.0.b')</span></span><br><span class="line"><span class="string">        [1, 2, 3]</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; class A(object):</span></span><br><span class="line"><span class="string">        ...     def __init__(self):</span></span><br><span class="line"><span class="string">        ...         self.x = self</span></span><br><span class="line"><span class="string">        ...         self.y = &#123;'a': 10&#125;</span></span><br><span class="line"><span class="string">        ...</span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(A(), 'x.x.x.x.x.x.y.a')</span></span><br><span class="line"><span class="string">        10</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(&#123;'a.b': &#123;'c': 1&#125;&#125;, 'a.b.c')</span></span><br><span class="line"><span class="string">        Traceback (most recent call last):</span></span><br><span class="line"><span class="string">            ...</span></span><br><span class="line"><span class="string">        LookupError: &#123;u'a.b': &#123;u'c': 1&#125;&#125; has no element at 'a'</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(&#123;'a.b': &#123;'Привет': 1&#125;&#125;, ['a.b', 'Привет'])</span></span><br><span class="line"><span class="string">        1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        &gt;&gt;&gt; deep_get(&#123;'a.b': &#123;'Привет': 1&#125;&#125;, 'a.b/Привет', separator='/')</span></span><br><span class="line"><span class="string">        1</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">    """</span></span><br><span class="line">    <span class="keyword">if</span> isinstance(path, basestring):</span><br><span class="line">        attributes = path.split(separator)</span><br><span class="line">    <span class="keyword">elif</span> isinstance(path, collections.Iterable):</span><br><span class="line">        attributes = path</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        attributes = [path]</span><br><span class="line"></span><br><span class="line">    LOOKUPS = [getattr, operator.getitem, <span class="keyword">lambda</span> obj, i: obj[int(i)]]</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">for</span> i <span class="keyword">in</span> attributes:</span><br><span class="line">            <span class="keyword">for</span> lookup <span class="keyword">in</span> LOOKUPS:</span><br><span class="line">                <span class="keyword">try</span>:</span><br><span class="line">                    obj = lookup(obj, i)</span><br><span class="line">                    <span class="keyword">break</span></span><br><span class="line">                <span class="keyword">except</span> (TypeError, AttributeError, IndexError, KeyError,</span><br><span class="line">                        UnicodeEncodeError, ValueError):</span><br><span class="line">                    <span class="keyword">pass</span></span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                msg = <span class="string">"&#123;obj&#125; has no element at '&#123;i&#125;'"</span>.format(obj=obj, i=i)</span><br><span class="line">                <span class="keyword">raise</span> LookupError(msg.encode(<span class="string">'utf8'</span>))</span><br><span class="line">    <span class="keyword">except</span> Exception:</span><br><span class="line">        <span class="keyword">if</span> _default_stub != default:</span><br><span class="line">            <span class="keyword">return</span> default</span><br><span class="line">        <span class="keyword">raise</span></span><br><span class="line">    <span class="keyword">return</span> obj</span><br></pre></td></tr></table></figure>


<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/2" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/2</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/17/tornado--yi-bu-shang-xia-wen-guan-li-%EF%BC%88stackcontext%EF%BC%89/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="bigfish">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="理想-咸鱼">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/17/tornado--yi-bu-shang-xia-wen-guan-li-%EF%BC%88stackcontext%EF%BC%89/" itemprop="url">tornado-异步上下文管理（StackContext）</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-10-17T13:18:50+08:00">
                2018-10-17
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Words count in article&#58;</span>
                
                <span title="Words count in article">
                  918
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">Reading time &asymp;</span>
                
                <span title="Reading time">
                  4
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="tornado-异步上下文管理（StackContext）"><a href="#tornado-异步上下文管理（StackContext）" class="headerlink" title="tornado - 异步上下文管理（StackContext）"></a>tornado - 异步上下文管理（StackContext）</h1><h2 id="初步使用"><a href="#初步使用" class="headerlink" title="初步使用"></a>初步使用</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">import</span> tornado.ioloop</span><br><span class="line"><span class="keyword">import</span> tornado.stack_context</span><br><span class="line"></span><br><span class="line">ioloop = tornado.ioloop.IOLoop.instance()</span><br><span class="line"></span><br><span class="line">times = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">callback</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run callback'</span></span><br><span class="line">    <span class="keyword">raise</span> ValueError(<span class="string">'except in callback'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">async_task</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">global</span> times</span><br><span class="line">    times += <span class="number">1</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run async task &#123;&#125;'</span>.format(times)</span><br><span class="line">    ioloop.add_callback(callback=callback)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        async_task()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'main exception &#123;&#125;'</span>.format(e)</span><br><span class="line">    <span class="keyword">print</span> <span class="string">'end'</span></span><br><span class="line"></span><br><span class="line">main()</span><br><span class="line">ioloop.start()</span><br></pre></td></tr></table></figure>

<p>异常没有在 main 中捕获：</p>
<pre><code>run async task 1
end
run callback
ERROR:root:Exception in callback &lt;function null_wrapper at 0x7f23ec300488&gt;
Traceback (most recent call last):
  File &quot;~/learn/tornado/tornado/ioloop.py&quot;, line 370, in _run_callback</code></pre><h2 id="包裹上下文"><a href="#包裹上下文" class="headerlink" title="包裹上下文"></a>包裹上下文</h2><p>使用 partial 生成新的函数, 最终调用的函数为 wrapper(callback)，在 wrapper 中捕获异常</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">import</span> tornado.ioloop</span><br><span class="line"><span class="keyword">import</span> tornado.stack_context</span><br><span class="line"><span class="keyword">import</span> functools</span><br><span class="line"></span><br><span class="line">ioloop = tornado.ioloop.IOLoop.instance()</span><br><span class="line"></span><br><span class="line">times = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">callback</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run callback'</span></span><br><span class="line">    <span class="keyword">raise</span> ValueError(<span class="string">'except in callback'</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrapper</span><span class="params">(func)</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        func()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'main exception &#123;&#125;'</span>.format(e)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">async_task</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">global</span> times</span><br><span class="line">    times += <span class="number">1</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run async task &#123;&#125;'</span>.format(times)</span><br><span class="line">    <span class="comment"># 使用 partial 生成新的函数</span></span><br><span class="line">    <span class="comment"># 最终 ioloop 调用的函数为 wrapper(callback)</span></span><br><span class="line">    ioloop.add_callback(callback=functools.partial(wrapper, callback))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        async_task()</span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'main exception &#123;&#125;'</span>.format(e)</span><br><span class="line">    <span class="keyword">print</span> <span class="string">'end'</span></span><br><span class="line"></span><br><span class="line">main()</span><br><span class="line">ioloop.start()</span><br></pre></td></tr></table></figure>

<p>异常被正确捕获：</p>
<pre><code>run async task 1
end
run callback
main exception except in callback</code></pre><h2 id="使用-tornado-stack-context-例子"><a href="#使用-tornado-stack-context-例子" class="headerlink" title="使用 tornado stack_context 例子"></a>使用 tornado stack_context 例子</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line"><span class="keyword">import</span> tornado.ioloop</span><br><span class="line"><span class="keyword">import</span> tornado.stack_context</span><br><span class="line"><span class="keyword">import</span> contextlib</span><br><span class="line"></span><br><span class="line">ioloop = tornado.ioloop.IOLoop.instance()</span><br><span class="line"></span><br><span class="line">times = <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">callback</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'Run callback'</span></span><br><span class="line">    <span class="comment"># 抛出的异常在 contextor 中被捕获</span></span><br><span class="line">    <span class="keyword">raise</span> ValueError(<span class="string">'except in callback'</span>)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">async_task</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">global</span> times</span><br><span class="line">    times += <span class="number">1</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'run async task &#123;&#125;'</span>.format(times)</span><br><span class="line">    <span class="comment"># add_callback, 会用之前保存的 (StackContext, contextor)，创建一个对象 StackContext(contextor)</span></span><br><span class="line">    <span class="comment"># ioloop 回调的时候使用 </span></span><br><span class="line">    <span class="comment"># with StackContext(contextor)</span></span><br><span class="line">    <span class="comment">#   callback</span></span><br><span class="line">    <span class="comment"># 从而 callback 函数也在 contextor 函数中执行，从而能够在 contextor 中捕获异常</span></span><br><span class="line">    <span class="comment"># 从而实现 async_task() 函数在 contextor 中执行，其引发的异常（其实是 callback）同时在 contextor 被捕获</span></span><br><span class="line">    ioloop.add_callback(callback=callback)</span><br><span class="line"></span><br><span class="line"><span class="meta">@contextlib.contextmanager</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">contextor</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'Enter contextor'</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">yield</span></span><br><span class="line">    <span class="keyword">except</span> Exception <span class="keyword">as</span> e:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'Handler except'</span></span><br><span class="line">        <span class="keyword">print</span> <span class="string">'exception &#123;&#125;'</span>.format(e)</span><br><span class="line">    <span class="keyword">finally</span>:</span><br><span class="line">        <span class="keyword">print</span> <span class="string">'Release'</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">()</span>:</span></span><br><span class="line">    <span class="comment">#使用StackContext包裹住contextor, 下面函数 async_task() 会在 contextor() 环境中执行</span></span><br><span class="line">    stack_context = tornado.stack_context.StackContext(contextor)</span><br><span class="line">    <span class="keyword">with</span> stack_context:</span><br><span class="line">        async_task()</span><br><span class="line">    <span class="keyword">print</span> <span class="string">'End'</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">main()</span><br><span class="line">ioloop.start()</span><br></pre></td></tr></table></figure>

<h3 id="tornado-stack-context-StackContext"><a href="#tornado-stack-context-StackContext" class="headerlink" title="tornado.stack_context.StackContext"></a>tornado.stack_context.StackContext</h3><p>tornado.stack_context 相当于一个上下文包裹器，它接收一个 context_factory 作为参数并保存<br>context_factory 是一个上下文类，拥有 <code>__enter__</code> <code>__exit__</code>方法</p>
<p>使用 with stack_context 时候，执行自己的 <code>__enter__</code><br><code>__enter__</code> 函数根据保存的 context_factory 创建一个 context 对象，并执行对象的 <code>__enter__</code>方法<br>StackContext 将 (StackContext, context_factory) 保存，将来执行回调的时候再创建一个 StackContext(context_factory) 来执行 call_back</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StackContext</span><span class="params">(object)</span>:</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__init__</span><span class="params">(self, context_factory)</span>:</span></span><br><span class="line">        self.context_factory = context_factory</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__enter__</span><span class="params">(self)</span>:</span></span><br><span class="line">        <span class="comment"># contexts 入栈</span></span><br><span class="line">        self.old_contexts = _state.contexts</span><br><span class="line">        <span class="comment"># _state.contexts is a tuple of (class, arg) pairs</span></span><br><span class="line">        _state.contexts = (self.old_contexts + </span><br><span class="line">                           ((StackContext, self.context_factory),))</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            self.context = self.context_factory()</span><br><span class="line">            <span class="comment"># 进入 context 对象的执行环境</span></span><br><span class="line">            self.context.__enter__()</span><br><span class="line">        <span class="keyword">except</span> Exception:</span><br><span class="line">            _state.contexts = self.old_contexts</span><br><span class="line">            <span class="keyword">raise</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">__exit__</span><span class="params">(self, type, value, traceback)</span>:</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">return</span> self.context.__exit__(type, value, traceback)</span><br><span class="line">        <span class="keyword">finally</span>:</span><br><span class="line">            <span class="comment"># contexts 出栈</span></span><br><span class="line">            _state.contexts = self.old_contexts</span><br></pre></td></tr></table></figure>

<h3 id="IOLoop-add-callback"><a href="#IOLoop-add-callback" class="headerlink" title="IOLoop.add_callback"></a>IOLoop.add_callback</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">add_callback</span><span class="params">(self, callback)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> self._callbacks:</span><br><span class="line">        self._wake()</span><br><span class="line">        self._callbacks.append(stack_context.wrap(callback))</span><br></pre></td></tr></table></figure>

<h3 id="IOLoop-start"><a href="#IOLoop-start" class="headerlink" title="IOLoop.start"></a>IOLoop.start</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">start</span><span class="params">(self)</span>:</span></span><br><span class="line">    <span class="keyword">if</span> self._stopped:</span><br><span class="line">        self._stopped = <span class="literal">False</span></span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    self._running = <span class="literal">True</span></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="comment"># Never use an infinite timeout here - it can stall epoll</span></span><br><span class="line">        poll_timeout = <span class="number">0.2</span></span><br><span class="line"></span><br><span class="line">        callbacks = self._callbacks</span><br><span class="line">        self._callbacks = []</span><br><span class="line">        <span class="keyword">for</span> callback <span class="keyword">in</span> callbacks:</span><br><span class="line">            <span class="comment"># 调用注册的 callback</span></span><br><span class="line">            self._run_callback(callback)</span><br></pre></td></tr></table></figure>

<h3 id="IOLoop-run-callback"><a href="#IOLoop-run-callback" class="headerlink" title="IOLoop._run_callback"></a>IOLoop._run_callback</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">_run_callback</span><span class="params">(self, callback)</span>:</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        callback()</span><br><span class="line">    <span class="keyword">except</span> (KeyboardInterrupt, SystemExit):</span><br><span class="line">        <span class="keyword">raise</span></span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        self.handle_callback_exception(callback)</span><br></pre></td></tr></table></figure>

<h3 id="stack-context-wrap"><a href="#stack-context-wrap" class="headerlink" title="stack_context.wrap"></a>stack_context.wrap</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">wrap</span><span class="params">(fn)</span>:</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> fn <span class="keyword">is</span> <span class="literal">None</span> <span class="keyword">or</span> fn.__class__ <span class="keyword">is</span> _StackContextWrapper:</span><br><span class="line">        <span class="keyword">return</span> fn</span><br><span class="line">    <span class="comment"># functools.wraps doesn't appear to work on functools.partial objects</span></span><br><span class="line">    <span class="comment">#@functools.wraps(fn)</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">wrapped</span><span class="params">(callback, contexts, *args, **kwargs)</span>:</span></span><br><span class="line">        <span class="keyword">if</span> contexts <span class="keyword">is</span> _state.contexts <span class="keyword">or</span> <span class="keyword">not</span> contexts:</span><br><span class="line">            callback(*args, **kwargs)</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment"># 包裹callback, 生成 StackContext(context_factory()) 对象</span></span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> _state.contexts:</span><br><span class="line">            new_contexts = [cls(arg) <span class="keyword">for</span> (cls, arg) <span class="keyword">in</span> contexts]</span><br><span class="line"></span><br><span class="line">        <span class="keyword">elif</span> (len(_state.contexts) &gt; len(contexts) <span class="keyword">or</span></span><br><span class="line">            any(a[<span class="number">1</span>] <span class="keyword">is</span> <span class="keyword">not</span> b[<span class="number">1</span>]</span><br><span class="line">                <span class="keyword">for</span> a, b <span class="keyword">in</span> itertools.izip(_state.contexts, contexts))):</span><br><span class="line">            <span class="comment"># contexts have been removed or changed, so start over</span></span><br><span class="line">            new_contexts = ([NullContext()] +</span><br><span class="line">                            [cls(arg) <span class="keyword">for</span> (cls,arg) <span class="keyword">in</span> contexts])</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            new_contexts = [cls(arg)</span><br><span class="line">                            <span class="keyword">for</span> (cls, arg) <span class="keyword">in</span> contexts[len(_state.contexts):]]</span><br><span class="line">        <span class="keyword">if</span> len(new_contexts) &gt; <span class="number">1</span>:</span><br><span class="line">            <span class="keyword">with</span> _nested(*new_contexts):</span><br><span class="line">                callback(*args, **kwargs)</span><br><span class="line">        <span class="keyword">elif</span> new_contexts:</span><br><span class="line">            <span class="comment"># 执行 StackContext，调用 fn</span></span><br><span class="line">            <span class="keyword">with</span> new_contexts[<span class="number">0</span>]:</span><br><span class="line">                callback(*args, **kwargs)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            callback(*args, **kwargs)</span><br><span class="line">    <span class="comment"># 返回偏函数，绑定 fn, _state.contexts</span></span><br><span class="line">    <span class="keyword">return</span> _StackContextWrapper(wrapped, fn, _state.contexts)</span><br></pre></td></tr></table></figure>

<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">_StackContextWrapper</span><span class="params">(functools.partial)</span>:</span></span><br><span class="line">    <span class="keyword">pass</span></span><br></pre></td></tr></table></figure>


<hr>
<p>Sync From: <a href="https://github.com/TheBigFish/blog/issues/1" target="_blank" rel="noopener">https://github.com/TheBigFish/blog/issues/1</a></p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
  </section>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/">&lt;i class&#x3D;&quot;fa fa-angle-left&quot;&gt;&lt;&#x2F;i&gt;</a><a class="page-number" href="/">1</a><span class="page-number current">2</span>
  </nav>



          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">bigfish</p>
              <p class="site-description motion-element" itemprop="description">一些简单的想法</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/%7C%7C%20archive">
              
                  <span class="site-state-item-count">18</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">5</span>
                  <span class="site-state-item-name">tags</span>
                </a>
              </div>
            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          <div class="links-of-author motion-element">
            
          </div>

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">bigfish</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.3</div>




<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>




        
<div class="busuanzi-count">
  <script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      访客数
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      人
    </span>
  

  
    <span class="site-pv">
      总访问量
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      次
    </span>
  
</div>








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.3"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.3"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.3"></script>



  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.3"></script>



  


  




	





  





  










  





  

  

  

  

  

  

</body>
</html>
